简单搞懂JS中的call、bind、apply 实现原理

147 阅读1分钟
/**
 * call
 * @param { any } context 参数1: 修改后的this指向
 * @param  {...any} args 参数2: 函数参数
 * @returns 返回执行结果
 */
Function.prototype.call = function call (context, ...args) {
  // 如果 context 是 null 或者 undefined 时, 自动指向 window (规范中, 非严格模式)
  context == null ? context = window : null;
  // 如果 context 不是对象类型, 需要构造为对象类型: 只有对象类型才能设置属性
  !/^(object|function)$/.test(typeof context) ? context = Object(context) : null;
  // 创建一个能够保证唯一性的属性名, 避免污染原始对象
  let self = this, res = null, key = Symbol('KEY');
  // context[key] 此时就是 fn.call() 中的这个 fn 函数
  context[key] = self;
  // 执行
  res = context[key](...args);
  // 移除新增的属性
  delete context[key];
  return res;
}

/**
 * bind
 * @param { any } context 参数1: 修改后的this指向
 * @param  {...any} args 参数2: 函数参数
 * @returns 返回修改this指向后的函数
 */
Function.prototype.bind = function bind (context, ...args) {
  // 这里的 this 就是 fn.bind() 中的这个 fn 函数
  let self = this;
  /**
   * @param  {...any} params 参数1: 函数参数
   */
  return function (...params) {
    // 调用 call 即可
    // 注: 需要把两部分参数拼接起来
    return self.call(context, ...params.concat(args));
  }
}

/**
 * apply
 * @param { any } context 参数1: 修改后的this指向
 * @param { array } args 参数2: 函数参数
 * @returns 返回执行结果
 */
Function.prototype.apply = function apply (context, args) {
  // 这里的 this 就是 fn.apply() 中的这个 fn 函数
  let self = this;
  // 调用 call 即可
  return self.call(context, ...args);
}