bind/apply/call的区别

80 阅读2分钟

介绍bind/apply/call

1. bind() 方法

bind() 方法创建一个新的函数,该函数会将其调用时的上下文(this 值)绑定到指定的对象,并可在调用时传入预设参数。

  • 作用:改变函数的执行上下文,并返回一个绑定了指定上下文的新函数。

  • 语法:function.bind(thisArg, arg1, arg2, ...)

  • 参数:

    • thisArg:要绑定到函数上下文的对象。
    • arg1, arg2, ...:要预设给新函数的参数列表。
  • 返回值:一个带有指定上下文和预设参数的新函数。

  • 示例:

    function greet(name) {
      console.log(`Hello, ${name}!`);
    }
    
    const person = {
      name: "John",
    };
    
    const sayHelloToPerson = greet.bind(person);
    sayHelloToPerson(); // 输出: Hello, John!
    

2. call() 方法

call() 方法调用一个函数,并设置函数内部的 this 值为指定的对象,还可以传递一系列参数。

  • 作用:改变函数的执行上下文,并立即执行该函数。

  • 语法:function.call(thisArg, arg1, arg2, ...)

  • 参数:

    • thisArg:要绑定到函数上下文的对象。
    • arg1, arg2, ...:要传递给函数的参数列表。
  • 返回值:函数的返回值(如果有)。

  • 示例:

    function greet() {
      console.log(`Hello, ${this.name}!`);
    }
    
    const person = {
      name: "John",
    };
    
    greet.call(person); // 输出: Hello, John!
    

3. apply() 方法

apply() 方法调用一个函数,并设置函数内部的 this 值为指定的对象,还可以传递一个数组作为参数。

  • 作用:改变函数的执行上下文,并立即执行该函数。

  • 语法:function.apply(thisArg, [argsArray])

  • 参数:

    • thisArg:要绑定到函数上下文的对象。
    • argsArray:一个包含要传递给函数的参数的数组。
  • 返回值:函数的返回值(如果有)。

  • 示例:

    function greet() {
      console.log(`Hello, ${this.name}!`);
    }
    
    const person = {
      name: "John",
    };
    
    greet.apply(person); // 输出: Hello, John!
    

这些方法的区别在于它们如何传递参数。bind() 方法创建一个新函数,不会立即执行,而是返回一个绑定了特定上下文和参数的函数。call()apply() 方法直接调用函数并立即执行,但它们之间的区别在于参数的传递方式。call() 方法接受一系列参数,而 apply() 方法接受一个数组作为参数。

手写bind/apply/call

手写 bind() 方法,注意点:

  • 返回一个新函数。
  • 新函数在调用时的上下文是绑定的对象。
  • 可以传递预设参数。
// 自定义 bind() 方法
Function.prototype.myBind = function (thisArg, ...args) {
  const originalFunc = this; // 原始函数
  return function (...innerArgs) {
    return originalFunc.apply(thisArg, [...args, ...innerArgs]);
  };
};

// 示例使用
function greet(name) {
  console.log(`Hello, ${name}!`);
}

const person = {
  name: "John",
};

const sayHelloToPerson = greet.myBind(person);
sayHelloToPerson("Alice"); // 输出: Hello, John!

手写实现 apply() 方法,可以遵循以下步骤:

  • 将 apply() 方法添加到 Function.prototype 中,以便所有函数都可以调用它。
  • 在自定义的 apply() 方法内部,将调用上下文设置为指定的对象,并执行该函数。
// 自定义 apply() 方法
Function.prototype.myApply = function (thisArg, argsArray) {
  const originalFunc = this; // 原始函数
  if (!Array.isArray(argsArray)) {
    throw new TypeError("argsArray must be an array");
  }
  return originalFunc.call(thisArg, ...argsArray);
};

// 示例使用
function greet(name, age) {
  console.log(`Hello, ${name}! You are ${age} years old.`);
}

const person = {
  name: "John",
};

greet.myApply(person, ["Alice", 25]); // 输出: Hello, John! You are 25 years old.


手写实现 call() 方法,可以按照以下步骤进行:

  • 将 call() 方法添加到 Function.prototype 中,以便所有函数都可以调用它。
  • 在自定义的 call() 方法内部,将调用上下文设置为指定的对象,并执行该函数。
// 自定义 call() 方法
Function.prototype.myCall = function (thisArg, ...args) {
  const originalFunc = this; // 原始函数
  thisArg = thisArg || window; // 如果没有传递上下文,则默认为全局对象
  thisArg.__fn__ = originalFunc; // 在上下文对象中创建一个临时属性来存储原始函数
  const result = thisArg.__fn__(...args); // 执行原始函数
  delete thisArg.__fn__; // 删除临时属性
  return result;
};

// 示例使用
function greet(name) {
  console.log(`Hello, ${name}!`);
}

const person = {
  name: "John",
};

greet.myCall(person, "Alice"); // 输出: Hello, Alice!