理解call,apply,bind的用法

125 阅读2分钟

#理解call,apply,bind的用法

先说函数用法

  • call——使用一个指定的 this 值和::单独给出的一个或多个参数::来::调用一个函数:: *function*.call(*thisArg*, *arg1*, *arg2*, …)
  • apply——::调用一个具有给定this值的函数::,以及以一::个数组(或 类数组对象 )的形式::提供的参数 *func*.apply(*thisArg, [argsArray*])
  • bind ——::创建一个新的函数::,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用;绑定函数自动适应于使用 new 操作符去构造一个由目标函数创建的新实例。::当一个绑定函数是用来构建一个值的,原来提供的 this 就会被忽略::。不过提供的参数列表仍然会插入到构造函数调用时的参数列表之前。

在上述用法中,我们总结一下三个函数的用法区别,call和apply在方法运行原理里的本质是相同的,只是传入的参数形式不同,都是即时调用一个给定this值的函数。bind不同于call和aplly的区别是bind不会立即调用函数,而是创建一个新的函数备份,该函数的this指向为指定的this值。特别注意的是,bind在绑定函数为构造函数的时候,函数的this指向始终指向备份函数生成的实例对象。

再说函数实现

在总结完用法后,我们对这三个函数的内部实现进行模拟。

call

Function.prototype.myCall = function (ctx) {
  //当传入的对象为空时 当前函数指向为全局
  if (typeof ctx == "null") {
    ctx = window;
  }
  const ctxObj = Object(ctx);
  //提取参数
  const args = Array.from(arguments).slice(1);
  //绑定函数到obj上
  ctxObj.fn = this;
  const res = ctxObj.fn(...args);
  delete ctxObj.fn;
  return res;
};

apply

Function.prototype.myApply = function (ctx) {
  if (typeof ctx == "null") {
    ctx = window;
  }
  const ctxObj = Object(ctx);
  //提取参数
  const args = arguments[1];
  //绑定函数到obj上
  ctxObj.fn = this;
  const res = ctxObj.fn(...args);
  delete ctxObj.fn;
  return res;
};

bind

//生成函数备份,当调用函数为普通函数时指向传入的对象,当调用函数为构造函数时指向使用该构造函数生成的实例;
Function.prototype.myBind = function (ctx) {
  if (typeof this !== "function") {
    throw new Error("调用对象不是函数!!!");
  }
  const self = this;
  //转换参数列表从类数组形式变为数组形式
  const args = Array.from(arguments).slice(1);
  //  生成备份函数
  let fn = function () {
    // 是否为实例对象
    const isNew = this instanceof self;
    //备份函数参数判断逻辑 以bind绑定的参数为主
    const fnArgs = args.length ? args : Array.from(arguments);
    return isNew ? new self(...fnArgs) : self.apply(ctx, fnArgs);
  };
  if (this.prototype) {
    fn.prototype = this.prototype;
  }
  return fn;
};