Skip to content

Apply & Call & Bind

Apply

用法

js
const info = { name: "ice", age: 25 };

function bar(city, country) {
  // info: ice 25 Hangzhou China
  console.log(`info: ${this.name} ${this.age} ${city} ${country}`);
}

// 传递一个对象,作为 bar 的 this
bar.apply(info, ["Hangzhou", "China"]);
  1. 函数 bar 调用了 apply 方法,故 apply 方法是在 Function 的显示原型上
  2. 当我们利用 apply 方法调用,传入的第一个参数是函数内部的 this
  3. 第二个参数,传入一个数组,会以此展开给 bar 函数接受

实现

js
Function.prototype.MyApply = function (context, arrayArgs) {
  // 1. 如果不是这些类型,把它包装为 Obj 类型
  if (typeof context !== "object" || typeof context !== "function") {
    context = Object(context);
  }

  // 2. 创建一个 symbol 属性,防止重复
  const fn = Symbol("fn");

  // 3. x.myApply() 隐式绑定,函数体内的 this 指向 x
  context[fn] = this;

  // 4. x 函数挂在了 context 上,所以内部的 this 指向已经变为 ctx
  const result = context[fn](...arrayArgs);

  // 5. 删除附加的 symbol
  delete context[fn];

  // 6. 返回返回值
  return result;
};

const info = { name: "ice", age: 25 };

function bar(city, country) {
  console.log(`info: ${this.name} ${this.age} ${city} ${country}`);
}

bar.MyApply(info, ["Hangzhou", "China"]);

Call

用法

  • 用法上与 apply 相似, 一个依次传递,一个传递数组
js
x.call(this, "a", "b", "c");
x.apply(this, ["a", "b", "c"]);

实现

js
Function.prototype.MyCall = function (context, ...thisArgs) {
  // 1. 不等于该类型,包装成对象类型
  if (typeof context !== "object" || typeof context !== "function") {
    context = Object(context);
  }

  // 2. 创建唯一的key
  const fn = Symbol("fn");

  // 3. x.MyCall(), x 挂载到 context 上
  context[fn] = this;

  // 4. 调用函数,并且展开参数
  const result = context[fn](...thisArgs);

  // 5. 删除属性
  delete context[fn];

  // 6. 返回
  return result;
};

function bar(city, country) {
  console.log(`info: ${this.name} ${this.age} ${city} ${country}`);
}

bar.MyCall({ name: "ice", age: 25 }, "Hangzhou", "China");

Bind

用法

js
function bar(city, country) {
  console.log(`info: ${this.name} ${this.age} ${city} ${country}`);
}

const bindBar = bar.bind({ name: "ice", age: 25 }, "Hangzhou");
bindBar("China");
  • x.bind(this, args) 第一个参数为 this,后面可选填参数, 返回一个新的函数 -> 携带了 this / 参数
  • 调用新的函数,也可以再次传递参数

实现

js
Function.prototype.MyBind = function (context, ...thisArgs1) {
  if (typeof context !== "object" || typeof context !== "function") {
    context = Object(context);
  }

  const fn = Symbol("fn");
  context[fn] = this;

  // 返回了一个新的函数
  return (...thisArgs2) => {
    const result = context[fn](...thisArgs1, ...thisArgs2);
    delete context[fn];

    return result;
  };
};

function bar(city, country) {
  console.log(`info: ${this.name} ${this.age} ${city} ${country}`);
}

const bindBar = bar.MyBind({ name: "ice", age: 25 }, "Hangzhou", "China");
bindBar();
  • 与 call/apply 不同的是
    • 它是返回了一个已经 bind this 的 fn 函数
    • 函数的传递可以分批或者一次性传入