ES6 箭头函数(Arrow Functions)最核心的特性之一就是它不绑定自己的 this
。箭头函数中的 this
指向是在函数被创建时就确定的,它继承自外层(包裹它的)普通函数或全局作用域的 this
值。这种机制被称为 this
的词法绑定(Lexical this
)。
这与传统的普通函数(使用 function
关键字定义)形成鲜明对比,普通函数的 this
是在函数被调用时动态确定的。
1. 箭头函数 this
的核心规则
- 没有自己的
this
:箭头函数在执行时,不会创建自己的this
上下文。 - 继承外层
this
:它会沿着作用域链向上查找,使用最近的非箭头函数的this
值。 - 创建时决定:
this
的指向在箭头函数被定义时就已经确定,无法通过call
、apply
或bind
方法改变。
2. 与普通函数的对比示例
场景一:作为对象方法
const person = {
name: 'Alice',
// 普通函数:this 指向调用者 (person)
greetNormal: function() {
console.log(this.name); // 'Alice'
},
// 箭头函数:this 不指向 person!
greetArrow: () => {
console.log(this.name); // undefined (在浏览器中通常是 window.name)
}
};
person.greetNormal(); // 'Alice'
person.greetArrow(); // undefined 或空字符串
- 解释:
greetArrow
是一个箭头函数,它没有自己的this
。它的外层是全局作用域(或模块作用域),所以this
指向全局对象(浏览器中是window
)。window
没有name
属性,因此输出undefined
。
场景二:在 setTimeout
或事件回调中
这是箭头函数 this
优势最明显的场景。
function Timer() {
this.seconds = 0;
// 普通函数作为回调:this 会丢失!
setInterval(function() {
this.seconds++; // 错误!这里的 this 通常指向全局对象或 undefined (严格模式)
console.log(this.seconds); // NaN 或报错
}, 1000);
// 箭头函数作为回调:完美继承外层 this!
setInterval(() => {
this.seconds++; // 正确!this 指向 Timer 实例
console.log(this.seconds); // 每秒输出递增的数字
}, 1000);
}
const timer = new Timer();
- 解释:第一个
setInterval
的回调是普通函数,当它执行时,this
被设置为调用它的环境(通常是全局对象),不再是Timer
实例。而箭头函数() => { ... }
的this
继承自外层的Timer
构造函数,因此this
正确地指向了Timer
的实例。
场景三:在数组方法(如 map
, filter
)中
const numbers = [1, 2, 3];
const multiplier = {
factor: 10,
// 普通函数:需要保存 this
multiplyNormal: function() {
const self = this; // 保存 this
return numbers.map(function(num) {
return num * self.factor; // 必须用 self,不能用 this
});
},
// 箭头函数:直接使用 this
multiplyArrow: function() {
return numbers.map(num => num * this.factor); // this 指向 multiplier 对象
}
};
console.log(multiplier.multiplyNormal()); // [10, 20, 30]
console.log(multiplier.multiplyArrow()); // [10, 20, 30]
- 解释:在
multiplyNormal
中,map
的回调是普通函数,它有自己的this
(不是multiplier
),所以必须用self = this
来保存外层的this
。而在multiplyArrow
中,箭头函数直接继承了multiplyArrow
方法的this
(即multiplier
对象),可以直接使用this.factor
。
3. 箭头函数 this
的“不可变性”
你无法通过 call
、apply
或 bind
来改变箭头函数的 this
指向。
const arrowFunc = () => console.log(this);
const obj = { name: 'Bob' };
// 以下调用都无法改变 arrowFunc 内部的 this
arrowFunc.call(obj); // 仍然输出全局对象的属性
arrowFunc.apply(obj); // 同上
arrowFunc.bind(obj)(); // 同上
4. 总结
- 箭头函数没有自己的
this
。 this
指向外层作用域的this
,在函数创建时就已确定(词法绑定)。- 不能用
call
、apply
、bind
改变其this
。 - 适用场景:
- 作为回调函数(如
setTimeout
,setInterval
, 事件处理器)。 - 在数组方法(
map
,filter
,reduce
)的回调中。 - 需要确保
this
指向外层函数的场景。
- 作为回调函数(如
- 不适用场景:
- 作为对象的方法(除非你明确知道
this
会指向全局)。 - 需要动态
this
的场景(如构造函数、需要this
指向调用者的函数)。 - 需要使用
arguments
对象的场景(箭头函数也没有自己的arguments
)。
- 作为对象的方法(除非你明确知道
简单来说,记住:箭头函数的 this
指向它被定义时所处的环境的 this
。这个特性使得它在处理回调时非常方便,避免了 this
丢失的问题。
THE END