GaoLi's Blog

ES6 箭头函数陷阱

在你使用箭头函数之前需要明确一个重要概念:箭头函数中的 this 总是指向定义时所在的对象,而不是运行时所在的对象。让我们通过以下代码来加深理解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// ES6
const A = function() {
setTimeout(() => {
console.log(this.name);
}, 1000);
};
A.call({ name: 'gaoli' }); // gaoli
// ES5
var A = function A() {
var _this = this;
setTimeout(function () {
console.log(_this.name);
}, 1000);
};
A.call({ name: 'gaoli' }); // gaoli

通过 ES5 语法转换,可以清楚知道箭头函数中的 this 其实是引用了父级作用域中的 this,那么在日常使用过程中箭头函数的这种特性会带来什么陷阱呢?

定义对象方法

1
2
3
4
5
6
7
8
9
const car = {
color: 'red',
printColor: () => {
console.log(this === window); // true
console.log(this.color); // undefined
}
};
car.printColor();

对象 car 并不能构成作用域,所以箭头函数中的 this 指向 window 对象。

定义原型方法

1
2
3
4
5
6
7
8
9
10
11
12
function Car() {
this.color = 'red';
};
Car.prototype.printColor = () => {
console.log(this === window); // true
console.log(this.color); // undefined
};
const car = new Car();
car.printColor();

与上例相同,箭头函数中的 this 并非指向 Car,而是指向 window 对象。

定义构造函数

1
2
3
4
5
const Car = () => {
this.color = 'red';
};
const car = new Car(); // Throws "TypeError: Car is not a constructor"

当执行 new 操作时,该例箭头函数中的 this 总是指向 window 对象而非新生成的实例对象,使得其作为构造函数非但没有什么意义,相反可能会造成很大歧义。

动态上下文的回调函数

1
2
3
$('#id').on('click', () => {
console.log(this === window); // true
});

平时在 DOM 元素上绑定事件监听时,我们总是习惯在事件触发回调中通过 this 获取当前 DOM 元素,然而该例中使用箭头函数作为事件处理函数,则会因其定义在全局环境中,导致 this 指向 window 对象。