Call、apply、bind

52 阅读3分钟

bind 方法和 call、apply 方法都是用来改变函数的 this 上下文的。

(1)bind 方法会创建一个新的函数,当被调用时,将设置其 this 关键字为提供的值,在提供的参数加上原函数的参数一起传入原函数执行。

(2)bind 方法不会立即执行函数,而是返回一个新的函数,这个新的函数的 this 值被绑定到了指定的对象,调用时也可以传入参数。同时使用 bind 方法可以实现柯里化,即将函数转化为接收部分参数的函数。

(3)call 方法在调用一个函数时会立即提供所有参数

总结:bind 创建一个新函数,call 和 apply 立即调用函数。call 和 apply 的区别在于参数的传递方式不同,call 传递参数列表,而 apply 传递参数数组。

手写实现call

Call和apply相同点:

  1. 两者都用于改变函数上下文,第一个参数就是用来指定函数执行时的上下文。

  2. 两者实现时都调用函数的内置函数[[Call]]。

  3. 第一个参数为null或undefined,则用全局对象替换this。

 

fun.call(this, arg1,arg2,...)

 (1) 参数: call函数的第一个参数是在 ‘fun’函数运行时指定的 this 值,它和我们函数内部的this 指向不是一回事

(2) 返回值: call函数的返回值,是调用call函数的函数返回值

Function.prototype.call (thisArg , arg1  , arg2, …  )

function myCall(context) {
  // 判断this是否是函数  
  if(typeof this !== 'function') {
    throw new Error('this is not a function');
  }
  // 形参不一定会传
  let context = context || window;
  // let args = Array.prototype.slice.call(arguments, 1);
  // call函数有传参,利用argument取参,但是要去除第一个
  let args = [...arguments].slice(1);
  // this 是一个函数  context是我们想改变指向的man对象
  // 调用person.getName 就使用this
  context.fn = this;
  // getName的函数 this 指向man
  let result = context.fn(args);
  // context.fn 并不是真正存在  所以用完后要删掉
  delete context.fn;
  return result;
}

person.getName.myCall(man); 

手写实现apply

Function.prototype.apply (thisArg, argArray)

Function.prototype.myApply = function (context, args) {
  // 默认不传就是window,
  let context = context || window;
  // 判断参数 有显示,没有先是空数组
  let args = args || [];
  context.fn = this;
  // 通过隐式绑定的方式调用函数
  let result = context.fn(...args);
  // 删除添加的属性
  delete context.fn;
  return result;
}

手写实现bind

bind方法允许我们绑定函数的上下文并返回一个新的函数. bind 方法会创建一个新的函数,当被调用时,将设置其 this 关键字为提供的值,在提供的参数加上原函数的参数一起传入原函数执行。

Function.bind(thisArg, arg1,arg2,...)

(1). 创建一个新函数。

(2). 将新函数的this值绑定为指定的thisArg值。

(3). 将新函数的参数与绑定函数的参数合并。

(4). 调用绑定函数,将绑定函数的结果返回给新函数。

注意:

与call和apply不一样的地方是,这里还需要设置一下返回的那个函数的原型,采用继承的方式,不能直接 = ,要采用一个中介函数fn来辅助改变_fn的原型。

function myBind(context) {
  context = context || window;
  if (typeof this !== "function") {
    return;
  }
  var self = this;
  // let args = [...arguments].splice(1); 
  var args = Array.prototype.slice(arguments, 1);
  var A = function() {};
  var B = function() {
    var _this = this instanceof A ?  this : context;
    return self.apply(_this, args.concat(Array.prototype.slice.call(arguments, 0)));
  }
  if (this.prototype) {
    A.prototype = this.prototype;
  }
  B.prototype = new A();
  return B;
}

以上是学习和总结。