# call apply bind模拟实现

call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。

TIP

备注:该方法的语法和作用与 apply() (opens new window) 方法类似,只有一个区别,就是 call() 方法接受的是一个参数列表,而 apply() 方法接受的是一个包含多个参数的数组

# call

采用rest参数实现

Function.prototype.call2 = function (context, ...args) {
  // 传入null时, 指向为window
  context = context || window;
  context.func = this;
  const result = context.func(...args);
  delete context.func;
  return result;
};

采用arguments 配合eval实现

Function.prototype.call3 = function (context) {
  // 传入null时, 指向为window
  context = context || window;
  context.func = this;

  const args = [];
  for (let i = 1, len = arguments.length; i < len; i++) {
    args.push('arguments[' + i + ']');
  }

  const result = eval('context.func(' + args + ')');
  delete context.func;
  return result;
};

# apply

apply相对简单

Function.prototype.apply2 = function (context, params) {
  // 传入null时, 指向为window
  context = context || window;
  context.func = this;

  const args = [];
  let result;
  if (!params) {
    result = context.func();
  } else {
    if (!Array.isArray(params)) {
      throw new TypeError('Expect an array param');
    }
    for (let i = 0, len = params.length; i < len; i++) {
      args.push('params[' + i + ']');
    }

    result = eval('context.func(' + args + ')');
  }

  delete context.func;
  return result;
};

# bind

bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

Function.prototype.bind2 = function (context) {
  const args = Array.prototype.slice.call(arguments, 1);
  const callback = this;

  const Noop = function () {};

  const newFunction = function () {
    const bindArgs = Array.prototype.slice.call(arguments);
    // 当作为构造函数时,this 指向实例,此时结果为 true,将绑定函数的 this 指向该实例,可以让实例获得来自绑定函数的值
    // 当作为普通函数时,this 指向 window,此时结果为 false,将绑定函数的 this 指向 context
    return callback.apply(
      this instanceof Noop ? this : context,
      args.concat(bindArgs)
    );
  };

  // 防止原型污染
  Noop.prototype = callback.prototype;
  newFunction.prototype = new Noop();

  return newFunction;
};

简便一点, 采用rest参数不考虑原型实现

Function.prototype.bind3 = function (context, ...args) {
  const callback = this;
  return function (...args2) {
    return callback.apply(context, args.concat(args2));
  };
};

再用rest参数配合箭头函数实现一点

const bind4 =
  (callback, context, ...args) =>
  (...args2) => {
    return callback.call(context, ...args, ...args2);
  };

上次更新: 1/22/2025, 9:39:13 AM