JavaScript 中的 this 指向哪里?
this 是一个 非常重要 但又 容易混淆 的概念。
this 关键字 的 指向 是根据 函数的调用方式 来确定的,而 不是 在函数定义时 就决定的。理解 this 的 绑定规则 非常关键,因为它决定了 函数内部 this 所 指向的 对象。
1 this 的默认绑定
当我们在 函数内部直接使用 this 时,如果 没有明确的绑定方式(比如 call、apply 或 bind),this 的 指向 通常取决于 执行环境。
1.1 在全局作用域中
- 在 非严格模式 下,
this会 指向 全局对象(在浏览器中是window); - 在 严格模式 (
'use strict') 下,this会是undefined。
// 示例代码 1
console.log(this); // 在浏览器中,输出 Window 对象
'use strict';
console.log(this); // 输出 undefined
1.2 在函数中
普通函数内部,this 也指向 全局对象(在浏览器中是 window),除非 该函数被作为 对象的方法 调用(见示例代码 3)。
// 示例代码 2
function showThis() {
console.log(this); // 在浏览器中,输出 window 对象
}
showThis();
2 this 的对象方法调用绑定
当一个函数 作为 对象的方法 调用时,this 会 指向 该对象。
// 示例代码 3
const person = {
name: "Alice",
greet: function() {
console.log(this.name);
}
};
person.greet(); // 输出 Alice,`this` 指向 person 对象
在上面的代码中,greet 方法作为 person 对象的方法 调用,所以 this 指向 person。
3 this 的构造函数绑定
当我们通过 new 关键字 创建 一个对象时,this 会指向 新创建的 对象。
// 示例代码 4
function Person(name) {
this.name = name;
}
const person1 = new Person("Alice");
console.log(person1.name); // 输出 Alice
在这个例子中,this 在构造函数中 指向 新创建的对象 person1。
4 this 的 call、apply 和 bind 方法绑定
call、apply 和 bind 都是 JavaScript 提供的 显式绑定 this 的方法。
4.1 call 方法
functionName.call(thisArg, arg1, arg2, ...);
call 方法 立即调用 函数,并且 可以指定 this 的指向。
// 示例代码 5
// 定义一个函数
function introduce(city, country) {
console.log(`Hello, my name is ${this.name}. I live in ${city}, ${country}.`);
}
// 创建一个对象
const person = {
name: "Alice"
};
// 使用 call 传递多个参数
introduce.call(person, "Paris", "France"); // Hello, my name is Alice. I live in Paris, France.
call 方法的 第一个参数 是 要绑定到 this 的 对象,后面 可以 传递参数 给函数。call 方法可以传递 任意数量 的参数。
4.2 apply 方法
functionName.apply(thisArg, [arg1, arg2, ...]);
apply 方法和 call 类似,不同的是 它的 参数 是以 数组的形式 传入。
// 示例代码 6
// 定义一个函数
function introduce(city, country) {
console.log(`Hello, my name is ${this.name}. I live in ${city}, ${country}.`);
}
// 创建一个对象
const person = {
name: "Alice"
};
// 使用 apply 传递多个参数
introduce.apply(person, ["Paris", "France"]);
使用 apply 处理不定数量的参数
假设我们有一个函数,想要计算多个数值的和,apply 可以很方便地实现。
// 示例代码 7
// 定义一个函数来求和
function sumAll() {
const total = Array.from(arguments).reduce((acc, num) => acc + num, 0);
console.log(`The total sum is: ${total}`);
}
// 创建一个对象
const person = {
name: "Charlie"
};
// 使用 apply 调用并传递多个参数
sumAll.apply(person, [1, 2, 3, 4, 5]); // The total sum is: 15
4.3 bind 方法
functionName.bind(thisArg, arg1, arg2, ...);
bind 方法 返回 一个 新的函数,该函数 绑定了 指定的 this 值,而 不会 立即执行。
// 示例代码 8
function greet() {
console.log(`Hello, ${this.name}`);
}
const person = { name: "Alice" };
const greetPerson = greet.bind(person);
greetPerson(); // 输出 Hello, Alice
bind 返回的是 一个 新函数,它 始终保持 指定的 this 值(即对象 person)。
bind 与预设参数
使用 bind 来 预设 一些 参数,这些预设参数 会在 新函数 调用时 自动传递。
// 示例代码 9
// 定义一个函数
function greet(city, country) {
console.log(`Hello, my name is ${this.name}. I live in ${city}, ${country}.`);
}
// 创建一个对象
const person = {
name: "Bob"
};
// 使用 bind 预设一个参数
const greetInParis = greet.bind(person, "Paris");
// 调用时只需要传入剩余的参数
greetInParis("France"); // Hello, my name is Bob. I live in Paris, France.
greetInParis是通过bind创建的一个 新函数,this被绑定到person对象,city参数 被预设为 "Paris";- 当调用
greetInParis时,只需要传入 剩余的参数 "France",city自动使用预设 的 "Paris"。
5 箭头函数的 this 绑定
箭头函数 与 普通函数 的一个 关键区别 是:箭头函数 没有 自己的 this,它会 继承 外部作用域 的 this。
// 示例代码 10
const person = {
name: "Alice",
greet: function() {
setTimeout(() => {
console.log(`Hello, ${this.name}`);
}, 1000);
}
};
person.greet(); // 输出 Hello, Alice
在上面的例子中,setTimeout 中的 箭头函数 继承了 greet 方法的 this,而 greet 函数 包含在对象中,也就是 person 对象方法的 this 指向 对象本身(即 person 对象)。
如果是 普通函数,this 将指向 setTimeout 的全局对象(window),导致无法访问 person.name。
6 this 与事件处理函数
在 事件处理函数 中,this 通常指向 触发事件的 元素(即 事件的 目标对象)。
// 示例代码 11
const button = document.querySelector("button");
button.addEventListener("click", function() {
console.log(this); // 输出 button 元素
});
如果使用 箭头函数,this 就 不会 指向 button,而是 继承自 外部作用域:
// 示例代码 12
button.addEventListener("click", () => {
console.log(this); // 输出外部作用域的 `this`,通常是 `window`
});
this 指向的规则总结
| 全局环境 | 普通函数调用 | 对象方法调用 | 构造函数调用 | bind, apply, bind | 箭头函数 | 事件处理 |
|---|---|---|---|---|---|---|
| 全局对象 | 全局对象(非严格模式) | 调用的对象 | 新创建的对象 | 显式传入的对象 | 继承外部作用域的 this | 触发事件的元素 |
浏览器中是 window | undefined(严格模式) |