this、call()、apply() 和 bind() 的魔法
I’m happy to translate the article for you, but I need the full text you’d like translated. Could you please paste the content (or the portion you want translated) here? I’ll keep the source line exactly as you provided and preserve all formatting, markdown, and code blocks.
亲爱的读者们 👋 – 欢迎回到本系列的第十篇文章
想象一下,你在派对上,有人喊道:“嘿,过来!”谁会回应?这取决于 谁在调用 以及 他们在看向谁。
在 JavaScript 中,this 关键字的工作方式正是如此。它是一个特殊标识符,指向 上下文——当前 调用 函数的对象。
有时你想控制 this 指向的对象。这时神奇的三剑客 call()、apply() 和 bind() 就派上用场了。
this in JavaScript – 简明解释
this是一个关键字,指向正在执行当前函数的对象。- 可以把它想象成一张秘密便条,告诉函数,“嘿,你现在正在为这个对象工作。”
简易规则: this 指向 调用函数的对象。
this 在普通函数中的使用
function showThis() {
console.log(this);
}
showThis(); // 在浏览器中:记录 window 对象当函数在全局上下文中调用时,this 指向 window。
"use strict";
function showThis() {
console.log(this);
}
showThis(); // undefined在 严格模式 下,JavaScript 不会默认指向全局对象——this 为 undefined。
记住: 在普通函数中,
this取决于函数的调用方式,而不是它的定义位置。
this 在对象内部(方法)
const person = {
name: "Satya",
greet() {
console.log(`Hello, I’m ${this.name}`);
}
};
person.greet(); // Hello, I’m Satya当函数是对象的属性(方法)时,this 指向该对象。
当你把方法分离出来会发生什么?
const greetFn = person.greet;
greetFn(); // Hello, I’m undefined(在非严格模式下会是 window.name)greetFn 现在是一个普通函数,所以 this 不再是 person。
这时 call、apply 和 bind 就派上用场了——它们让我们 显式设置 this 的值。
call()、apply() 与 bind() – 控制 this
call()
- 作用: 使用指定的
this值并 逐个 传入参数来调用函数。 - 语法:
functionName.call(thisArg, arg1, arg2, …)
const person1 = { name: "Raj" };
const person2 = { name: "Priya" };
function introduce(city, country) {
console.log(`${this.name} from ${city}, ${country}`);
}
introduce.call(person1, "Delhi", "India"); // Raj from Delhi, India
introduce.call(person2, "Mumbai", "India"); // Priya from Mumbai, India实际例子
const car = {
brand: "Toyota",
getDetails(model) {
console.log(`${this.brand} ${model}`);
}
};
const anotherCar = { brand: "Honda" };
car.getDetails.call(anotherCar, "Civic"); // Honda Civic我们借用了 car.getDetails,并在 anotherCar 上作为 this 调用它。
apply()
- 作用: 与
call()相同,只是参数以 数组(或类数组对象)的形式提供。 - 语法:
functionName.apply(thisArg, [argsArray])
introduce.apply(person1, ["Delhi", "India"]); // Raj from Delhi, India
introduce.apply(person2, ["Mumbai", "India"]); // Priya from Mumbai, India何时使用 apply
- 参数已经是数组。
- 需要传入可变数量的参数。
const numbers = [10, 20, 30, 40];
console.log(Math.max.apply(null, numbers)); // 40(这里 this 并不重要,所以传 null。)
bind()
- 作用: 不 立即调用函数。它返回一个 新函数,该函数的
this永久绑定为提供的值(并可预先填充参数)。 - 语法:
const boundFn = functionName.bind(thisArg, arg1, arg2, …)
const person = { name: "Satya" };
function greet(greeting) {
console.log(`${greeting}, I’m ${this.name}`);
}
const boundGreet = greet.bind(person, "Hello");
boundGreet(); // Hello, I’m Satya实际例子
const user = {
name: "Amit",
sayHi() {
console.log(`Hi, ${this.name}`);
}
};
// 将方法传给按钮的点击处理函数
const sayHiFn = user.sayHi.bind(user);
// 以后调用 sayHiFn 时,仍然使用 `user` 作为 this
sayHiFn(); // Hi, Amit如果不使用 bind,直接传递 user.sayHi 会导致 this 变成按钮元素(或全局对象)。
快速比较表
| 方法 | 函数何时被调用? | 参数如何传递? | 典型使用场景 |
|---|---|---|---|
call() | 立即 | 逐个,以逗号分隔 | 已知参数并希望立即调用 |
apply() | 立即 | 作为数组(或类数组) | 参数已经在数组中,或参数数量可变 |
bind() | 稍后(返回一个新函数) | 逐个(可预先填充) | 需要一个 this 固定的函数用于回调、事件处理等 |
简单助记符
- Call – 逗号分隔的参数。
- Apply – 数组参数。
- Bind – 借用并绑定以供以后使用。
关键要点
this总是指向 调用函数的对象。- 在 普通函数(非方法)中,
this是全局对象(在严格模式下为undefined)。 - 在 方法 中,
this是调用该方法的对象。 call()和apply()立即调用 函数,并使用指定的this。bind()返回一个新函数,其this被永久设定,可在以后调用。- 当需要 逗号分隔的参数 时使用
call,需要 数组参数 时使用apply,需要一个带固定上下文的可复用函数时使用bind。
理解 this 以及这三种方法可以帮助你避免许多 bug,并让你在控制函数执行时拥有超能力。
练习 上面的示例,尝试编写自己的代码,你会发现对 JavaScript 上下文的信心与日俱增! 🚀
很快这将成为你的第二天性。
希望你喜欢这篇博客。如果有任何错误或改进建议,欢迎告诉我。
你可以在 LinkedIn 和 X 上找到我——我会在那里发布更多内容。