call bind apply

137 阅读4分钟

callbindapply 是 JavaScript 中 函数调用 的三个重要方法,它们都用于改变函数的 执行上下文(this) ,即改变函数内部 this 指向的对象。

call方法

定义:

call 方法允许你指定 this 上下文并立即调用该函数。call 方法的语法如下:

func.call(thisArg, arg1, arg2, ...);
  • thisArg:表示函数执行时 this 的值。

  • arg1, arg2, ...:是传递给函数的参数,这些参数会被逐一传递给原函数。 特点:

  • 立即执行:调用 call 时,函数会立即执行。

  • 可以传参:你可以通过 call 传递多个参数给目标函数。

例子:

function greet(greeting, punctuation) {
  console.log(greeting + ', ' + this.name + punctuation);
}

const person = { name: 'Alice' };

// 使用 call
greet.call(person, 'Hello', '!');  // 输出:Hello, Alice!

解析

  • call 的第一个参数是 thisArg,它会绑定到 greet 函数的 this 上。
  • 接下来的参数是传递给 greet 函数的参数。

apply 方法

定义:

apply 方法与 call 方法非常相似,区别在于 参数传递的方式不同apply 接收一个参数数组作为参数,而 call 是逐个传递参数。

func.apply(thisArg, [arg1, arg2, ...]);
  • thisArg:表示函数执行时 this 的值。

  • [arg1, arg2, ...]:一个包含参数的数组。

例子:

function greet(greeting, punctuation) {
  console.log(greeting + ', ' + this.name + punctuation);
}

const person = { name: 'Alice' };

// 使用 apply
greet.apply(person, ['Hello', '!']);  // 输出:Hello, Alice!

bind 方法

定义:

bind 方法与 callapply 的不同之处在于:bind 不会立即执行函数,而是返回一个新的函数,该函数在调用时会使用指定的 this 值和传入的参数。

const newFunc = func.bind(thisArg, arg1, arg2, ...);
  • thisArg:表示函数执行时 this 的值。

  • arg1, arg2, ...:是传递给新函数的参数。

特点:

  • 不会立即执行:与 callapply 不同,bind 不会立即执行函数,而是返回一个新的函数,直到该函数被调用时才执行。
  • 可以提前绑定参数:你可以为返回的函数提供一些预设的参数,返回的函数会将这些预设的参数与后续调用时传入的参数一起使用
function greet(greeting, punctuation) {
  console.log(greeting + ', ' + this.name + punctuation);
}

const person = { name: 'Alice' };

// 使用 bind
const greetPerson = greet.bind(person, 'Hello');
greetPerson('!');  // 输出:Hello, Alice!

解析

  • bind 返回一个新的函数 greetPerson,该函数已经绑定了 thisgreeting 参数。
  • 当我们调用 greetPerson 时,传入 ! 作为第二个参数,最后输出 Hello, Alice!

callapplybind 之间的主要区别

特性callapplybind
执行时机立即执行立即执行返回一个新的函数,延迟执行
参数传递方式参数逐个传递参数通过数组传递参数通过链式传递(可以部分预设)
返回值函数的返回值函数的返回值返回一个新的函数

练习

  1. 使用 call 改变 this

问题:

有一个 person 对象,包含 namegreet 方法。通过 call 方法,创建一个新的 employee 对象,并调用 greet 方法,使其显示正确的 this 值。

const person = {
  name: 'Alice',
  greet: function() {
    console.log('Hello, ' + this.name);
  }
};

const employee = {
  name: 'Bob'
};

// 使用 call 改变 greet 函数中的 this

要求:

  • 通过 callperson.greetthis 指向 employee
  1. 使用 apply 改变 this

问题:

有一个 car 对象,它有一个 drive 方法,可以打印出 this 对象的属性 model。通过 apply 方法,借用 drive 方法并输出 car2 对象的 model

const car = {
  model: 'Tesla',
  drive: function() {
    console.log(this.model + ' is driving');
  }
};

const car2 = {
  model: 'BMW'
};

// 使用 apply 改变 this 的指向

要求:

  • 通过 apply 改变 drive 函数的 this,并确保 car2model 被正确输出。
  1. 使用 bind 创建新的函数

问题:

有一个 counter 对象,它有一个 increment 方法,用于递增 count。请通过 bind 创建一个新的 incrementByTwo 方法,并将其应用于 counter 对象。

const counter = {
  count: 0,
  increment: function() {
    this.count++;
    console.log(this.count);
  }
};

// 使用 bind 创建新的函数 incrementByTwo

要求:

  • 通过 bind 创建一个新函数,使其递增 2 次,而不是 1 次。

答案:

const counter = {
  count: 0,
  increment: function() {
    this.count++;
    console.log(this.count);
  }
};

// 使用 bind 和闭包来创建每次递增 2 的方法
const incrementByTwo = function() {
  this.increment();
  this.increment();
}.bind(counter);

incrementByTwo(); // 输出: 1, 2
incrementByTwo(); // 输出: 3, 4
incrementByTwo(); // 输出: 5, 6
  1. bindcall 的结合使用

问题:

有一个 person 对象,包含 namegreet 方法。通过 bindcall 组合使用,先使用 bind 部分预设参数,再通过 call 调用函数。

const person = {
  name: 'Charlie',
  greet: function(greeting, punctuation) {
    console.log(greeting + ', ' + this.name + punctuation);
  }
};

// 使用 bind 和 call 组合

要求:

  • 使用 bind 先将 this 绑定到 person,并预设一个 greeting 参数。
  • 使用 call 传递剩余的 punctuation 参数。

答案:

const greetPerson = person.greet.bind(person, 'Hello');
greetPerson.call(person,'!');  // 输出:Hello, Charlie!