前端重学之路——bind、call、apply

今天来重温一下更改this指向的三种方法bind, call, apply。

突然面试被问到了,bind和call的区别?直接一脸懵逼,后来查了一下:bind改变this指向之后回返回一个函数,不会立即执行,需要手动触发一下。

call、apply、bind正常用法


let user = {
  birthday: '2/25'
}
var test = getData.bind(user);
function getData(name, age) {
  console.log('name', name);
  console.log('age', age);
  console.log('this.birthday', this.birthday);
}
// call和apply只是传入方式不同,call是列表,apply是数组
getData.call(user, 'tian', '22');
getData.apply(user, ['tian', '22']);
test(); // this.birthday 2/25

call、apply、bind模拟方法


call实现方法

// 原理是我们可以通过给user创建个gatData方法,然后执行完后再删除来模拟更改this指向的操作。
Function.prototype.call = function (context) {
  // 获得this指向的对象
  var cxt = context || window;
  // 改变传入对象函数的this指向
  cxt.fn = this;
  /* 获得传入对象后面的参数
    arguments: [对象,参数1,参数2]
    arguments.slice(1): [参数1, 参数2]
  **/
  var reuslt;
  var args;
  if (arguments[1]) {
    args = [...arguments]. slice(1);
    result = cxt.fn(...args);
  } else {
    result = cxt.fn();
  }
  // 将参数传入函数
  delete cxt.fn;
  return result
}

apply实现方法

// 原理相同,但是不同的是,apply接收参数是数组形式,所以只需要获得数组参数即可
Function.prototype.apply = function (context) {
  var ctx = context || window;
  ctx.fn = this;
  var result;
  if (arguments[1]) {
    result = ctx.fn(... arguments[1]);
  } else {
    result = cxt.fn()
  }
  delete ctx.fn;
  return result
}

bind实现方法

 // 最后bind实现起来就比较简单,不需要各种传参数之类的,只需要注意当前环境必须是function
Function.prototype.bind = function (context) {
  if (typeof this !== 'function') {
    throw new TypeError('Error')
  }
  var _this = this
  var args = [...arguments].slice(1)
  // 返回一个函数
  return function F() {
    // 因为返回了一个函数,我们可以 new F(),所以需要判断
    if (this instanceof F) {
      return new _this(...args, ...arguments)
    }
    return _this.apply(context, args.concat(...arguments))
  }
}

3种方法都是能改变this的指向,平时可以根据需求自由选择~
今天就重温到这里,明天再见

你可能感兴趣的:(前端重学之路——bind、call、apply)