call / apply / bind

Function.prototype.call

Function.prototype.myCall = function (context, ...args) {
  if (typeof this !== "function") {
    throw new TypeError("error");
  }

  context = context || window;
  context.fn = this;
  var result = context.fn(...params);
  delete context.fn;
  return result;
};

Function.prototype.apply

Function.prototype.myApply = function (context, args) {
  if (typeof this !== "function") {
    throw new TypeError("error");
  }

  context = context || window;
  context.fn = this;

  let result;
  if (argsArray) {
    result = context.fn(...argsArray);
  } else {
    result = context.fn();
  }
  delete context.fn;
  return result;
};

Function.prototype.bind

/**
 * bind 函数的作用是创建一个新的函数,绑定 this 值和部分参数
 *
 * 使用 new 操作符调用函数时,会创建一个新对象,并且这个对象的原型指向构造函数的 prototype 属性。
 * 这时候,构造函数内部的 this 会指向这个新对象。如果绑定的函数被用作构造函数,这时候的 this 应该指向新创建的对象,
 * 而不是之前绑定的那个 context。所以,这时候需要忽略之前绑定的 this,
 * 否则可能会导致原型链的问题或者属性被错误地添加到绑定的对象上,而不是新创建的实例上
 * @param {*} context
 * @param  {...any} outerArgs
 * @returns
 */
Function.prototype.myBind = function (context, ...args) {
  if (typeof this !== "function") {
    throw new TypeError("this is not a function");
  }

  const self = this;
  const bindFn = function (...innerArgs) {
    // 使用 this instanceof bindFn 判断是否被 new 操作符调用
    return self.apply(this instanceof bindFn ? this : context, [...outerArgs, ...innerArgs]);
  };

  bindFn.prototype = Object.create(this.prototype);

  return bindFn;
};

常见面试题

  1. call 和 apply 的区别?
  2. 手写 call?
  3. 手写 apply?
  4. 手写 bind?