在 JavaScript 中,this
是一个特殊关键字,其值取决于函数的 调用方式 而非定义位置。它的行为遵循一套明确的规则,以下是核心规则和示例:
1. 默认绑定(独立函数调用)
当函数独立调用时(不作为方法、构造函数等),this
指向全局对象:
- 浏览器中:
window
- Node.js 中:
global
function show() {
console.log(this); // 浏览器:Window / Node.js:global
}
show(); // 独立调用
严格模式('use strict'
)下:this
为 undefined
。
2. 隐式绑定(方法调用)
当函数作为对象方法调用时,this
指向 调用该方法的对象:
const user = {
name: "Alice",
greet() {
console.log(`Hello, ${this.name}!`);
}
};
user.greet(); // "Hello, Alice!"(this = user)
⚠️ 易错点:绑定丢失
若将方法赋值给变量后调用,会丢失原始绑定,退回到默认绑定:
const greet = user.greet;
greet(); // "Hello, undefined!"(this 指向全局)
3. 显式绑定(call / apply / bind)
通过 call()
、apply()
或 bind()
强制指定 this
:
function greet() {
console.log(`Hello, ${this.name}!`);
}
const alice = { name: "Alice" };
const bob = { name: "Bob" };
// call/apply 立即调用
greet.call(alice); // "Hello, Alice!"(this = alice)
greet.apply(bob); // "Hello, Bob!"(this = bob)
// bind 创建新函数(永久绑定)
const boundGreet = greet.bind(alice);
boundGreet(); // "Hello, Alice!"
4. new 绑定(构造函数)
使用 new
调用构造函数时,this
指向 新创建的对象:
function Person(name) {
this.name = name; // this = 新对象
}
const alice = new Person("Alice");
console.log(alice.name); // "Alice"
5. 箭头函数:词法作用域绑定
箭头函数 没有自己的 this
,它会继承外层作用域的 this
(定义时绑定,非调用时):
const user = {
name: "Alice",
greet: function() {
// 普通函数:this = user
setTimeout(() => {
console.log(`Hello, ${this.name}!`); // this 继承自 greet
}, 100);
}
};
user.greet(); // "Hello, Alice!"(箭头函数捕获了 user)
⚠️ 注意:
- 箭头函数的
this
不可通过call/bind
修改。 - 对象字面量、类中的箭头函数会绑定到外层作用域(可能是全局)。
特殊场景总结
场景 | this 指向 | 示例 |
---|---|---|
独立函数调用 | 全局对象(严格模式为 undefined ) | func() |
对象方法调用 | 调用该方法的对象 | obj.method() |
call /apply /bind | 显式指定的对象 | func.call(ctx) |
new 构造函数 | 新创建的对象实例 | new Constructor() |
箭头函数 | 外层词法作用域的 this | () => { ... } |
DOM 事件处理 | 触发事件的元素 | button.onclick = func |
常见问题解决技巧
-
方法绑定丢失:用
bind()
或箭头函数固定this
。// 方法1: bind const boundMethod = obj.method.bind(obj); // 方法2: 箭头函数 obj.method = () => { ... };
-
回调函数中的
this
:- 使用箭头函数保留外层
this
。 - 显式绑定:
setTimeout(function() {...}.bind(this), 100)
。
- 使用箭头函数保留外层
-
类中的方法:使用箭头函数或手动绑定,避免丢失
this
:class Counter { count = 0; // 方案1: 类字段(箭头函数) increment = () => { this.count++; }; // 方案2: 构造函数中绑定 constructor() { this.decrement = this.decrement.bind(this); } decrement() { this.count--; } }
终极秘诀
this
的值在函数调用时确定,而非定义时。
始终问自己:这个函数是如何被调用的?
obj.func()
→this = obj
func()
→this = 全局/undefined
new Func()
→this = 新对象
- 箭头函数 → 继承外层
this