JavaScript this 绑定规则
this 是 JavaScript 中最复杂的概念之一,它的值在运行时确定,遵循四条绑定规则。
this 是什么
this 是函数执行上下文的一个属性,在函数调用时确定,而非定义时。
JavaScript
function foo() {
console.log(this);
}
foo(); // window(非严格模式)
foo(); // undefined(严格模式)
四条绑定规则
1. 默认绑定
独立调用时,this 指向全局对象(严格模式为 undefined)。
JavaScript
function foo() {
'use strict';
console.log(this); // undefined
}
function bar() {
console.log(this); // window(非严格模式)
}
2. 隐式绑定
函数作为对象方法调用时,this 指向调用者。
JavaScript
const obj = {
name: 'obj',
greet: function() {
console.log(this.name);
}
};
obj.greet(); // 'obj' - obj 调用 greet
// ⚠️ 隐式丢失
const fn = obj.greet;
fn(); // undefined - 独立调用,默认绑定
3. 显式绑定
使用 call、apply、bind 显式指定 this。
JavaScript
const obj = { name: 'obj' };
function greet(greeting) {
console.log(`${greeting}, ${this.name}`);
}
// call
greet.call(obj, 'Hello'); // 'Hello, obj'
// apply
greet.apply(obj, ['Hi']); // 'Hi, obj'
// bind
const boundGreet = greet.bind(obj);
boundGreet('Hey'); // 'Hey, obj'
call/apply/bind 对比
| 方法 | 执行方式 | 参数形式 |
|---|---|---|
| call | 立即执行 | 逐个传递 |
| apply | 立即执行 | 数组传递 |
| bind | 返回新函数 | 逐个传递 |
4. new 绑定
使用 new 调用构造函数时,this 指向新创建的对象。
JavaScript
function Person(name) {
this.name = name;
}
const p = new Person('Alice');
console.log(p.name); // 'Alice'
// new 执行过程
// 1. 创建空对象
// 2. 设置原型链
// 3. 执行构造函数(this 指向新对象)
// 4. 返回对象(若构造函数无返回值)
绑定优先级
JavaScript
new 绑定 > 显式绑定 > 隐式绑定 > 默认绑定
优先级示例
JavaScript
function foo(something) {
this.a = something;
}
const obj = {};
// 显式绑定
const boundFoo = foo.bind(obj);
boundFoo(1);
console.log(obj.a); // 1
// new 绑定优先级更高
const bar = new boundFoo(2);
console.log(obj.a); // 1(未改变)
console.log(bar.a); // 2(new 创建了新对象)
箭头函数的 this
词法绑定
箭头函数没有自己的 this,继承外层作用域的 this。
JavaScript
const obj = {
name: 'obj',
greet: function() {
const arrow = () => {
console.log(this.name); // 'obj' - 继承自 greet
};
arrow();
}
};
obj.greet();
解决回调中的 this 问题
JavaScript
const obj = {
name: 'obj',
greet: function() {
// ❌ 普通函数丢失 this
setTimeout(function() {
console.log(this.name); // undefined
}, 100);
// ✅ 箭头函数保留 this
setTimeout(() => {
console.log(this.name); // 'obj'
}, 100);
// ✅ bind 显式绑定
setTimeout(function() {
console.log(this.name);
}.bind(this), 100);
}
};
箭头函数不能改变 this
JavaScript
const arrow = () => {
console.log(this);
};
const obj = { name: 'obj' };
arrow.call(obj); // 仍是外层 this
arrow.apply(obj); // 仍是外层 this
arrow.bind(obj)();// 仍是外层 this
new arrow(); // TypeError: arrow is not a constructor
常见陷阱
1. 隐式丢失
JavaScript
const obj = {
name: 'obj',
greet: function() {
console.log(this.name);
}
};
// 赋值后丢失绑定
const fn = obj.greet;
fn(); // undefined
// 回调中丢失
function doSomething(callback) {
callback();
}
doSomething(obj.greet); // undefined
2. 对象引用链
JavaScript
const obj = {
name: 'obj',
inner: {
name: 'inner',
greet: function() {
console.log(this.name);
}
}
};
obj.inner.greet(); // 'inner' - 最近的对象引用
3. 原型链上的 this
JavaScript
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log(this.name);
};
const p = new Person('Alice');
p.greet(); // 'Alice' - this 是 p,不是 prototype
4. 类中的 this
text
class Counter {
constructor() {
this.count = 0;
}
increment() {
this.count++;
}
start() {
// ❌ 丢失 this
// setInterval(this.increment, 1000);
// ✅ 箭头函数
setInterval(() => this.increment(), 1000);
// ✅ bind
// setInterval(this.increment.bind(this), 1000);
}
}
判断 this 的步骤
text
1. 函数是否 new 调用? → this 是新对象
2. 函数是否 call/apply/bind? → this 是绑定的对象
3. 函数是否作为方法调用? → this 是调用对象
4. 是否是箭头函数? → this 是外层 this
5. 默认绑定 → 全局对象(严格模式 undefined)
要点总结
| 规则 | this 指向 | 优先级 |
|---|---|---|
| 默认绑定 | 全局/undefined | 最低 |
| 隐式绑定 | 调用对象 | 低 |
| 显式绑定 | 指定对象 | 高 |
| new 绑定 | 新对象 | 最高 |
| 箭头函数 | 词法作用域 | 特殊 |
- this 在调用时确定,非定义时
- 箭头函数没有 this,继承外层
- 优先级:new > 显式 > 隐式 > 默认
- 注意隐式丢失,使用 bind 或箭头函数修复
📝 发现内容有误?点击此处直接编辑