手写call apply bind方法

231 阅读1分钟

手写call apply bind方法

相同点:改变this指向

不同点:传参列表不同

call方法

  • fn.call(this, a, b,..)
/**
 * call方法会立即执行
 * @param {*} ctx 改变后的this指向的对象
 * @param  {...any} args 其他参数
 */
Function.prototype.myCall = function (ctx, ...args) {
  // 保存调用者(原函数)
  const self = this;

  // 判断ctx是否存在
  ctx = ctx === undefined || ctx === null ? globalThis : Object(ctx)

  // 创建唯一值避免覆盖原有属性
  const key = Symbol();

  // 将原函数保存在ctx中,设置不可枚举
  Object.defineProperty(ctx, {
    value: self,
    enumerable: false,
  })

  // 执行原函数,拿到返回值
  const result = ctx[key](...args);

  // 执行后删除
  delete ctx[key];

  // 返回原函数的返回值
  return result;
};

apply方法

  • fn.apply(this, [a, b,..])
/**
 * apply方法会立即执行
 * @param {*} ctx 改变后的this指向的对象
 * @param {*} params 其他参数 类型为数组
 */
Function.prototype.myApply = function (ctx, params = []) {
  // 判断参数类型
  if (!Array.isArray(params)) {
    throw "参数必须为数组";
  }

  // 保存调用者(原函数)
  const self = this;

  // 判断ctx是否存在
  ctx = ctx === undefined || ctx === null ? globalThis : Object(ctx)

  // 创建唯一值避免覆盖原有属性
  const key = Symbol();

  // 将原函数保存在ctx中,设置不可枚举
  Object.defineProperty(ctx, {
    value: self,
    enumerable: false,
  })

  // 执行原函数,拿到返回值
  const result = ctx[key](...params);

  // 执行后删除
  delete ctx[key];

  // 返回原函数的返回值
  return result;
};

bind方法

  • let res = fn.bind(this, a, b,..)
  • res(c, d,...)
/**
 * bind 返回一个新的函数
 * @param {*} ctx 改变后的this指向的对象
 * @param  {...any} args 其他参数
 */
Function.prototype.myBind = function (ctx, ...args) {
  // 保存调用者(原函数)
  const self = this;

  return function (...args2) {
    // 判断ctx是否存在
    ctx = ctx === undefined || ctx === null ? globalThis : Object(ctx)

    // 创建唯一值避免覆盖原有属性
    const key = Symbol();

    // 将原函数保存在ctx中,设置不可枚举
    Object.defineProperty(ctx, {
      value: self,
      enumerable: false,
    })

    // 执行原函数,拿到返回值
    const result = ctx[key](...args.concat(...args2));

    // 执行后删除
    delete ctx[key];

    // 返回原函数的返回值
    return result;
  };
};