箭头函数和`this`关键字

部分内容翻译自:文章

=> 箭头符号已经是比较常用的一个符号之一,而它与function生成的函数比较有一定的差别,这篇文章来总结一下。

箭头函数(Arrow Functions)

箭头函数的诞生为了简化函数的作用域并且让this使用得更加直观。

this=>函数里的指向

在谈得更深入之前,我们需要有一个很清晰的认知关于this是如何绑定ES5代码的。

如果this是在一个object的方法里面(一个属于一个objectfunction),那么它的指向是哪里呢?

1
2
3
4
5
6
7
8
9
const bunny = {
name: 'Usagei',
showName: function () {
alert(this.name)
}
}

bunny.showName()
// Usagei

没错!它会指向当前的object。后面会解释为什么。
再来,如果this在方法里的函数里面呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const bunny = {
name: 'Usagei',
task: ['transform', 'eat cake', 'blow kisses'],
showTasks: function () {
this.tasks.forEach(function(task) {
alert(this.name + " want to " + task)
})
}
}

bunny.showTasks()
// [object Window] wants to transform
// [object Window] wants to eat cake
// [object Window] wants to blow kisses

可以看到,方法内的函数体中的this并没有指向object本身,而是指向了全局作用域,在这里也就是我们的window对象(如果在node.js的话是global对象)

为什么this会绑定到了window object呢?因为this总是会指向它所在函数的所有者,在这个case里面,因为它超出了作用域

当它在object的一个方法体内,这个方法的拥有者是对象,所以this指向的是object。但是在这个方法里面再内嵌一个函数,不管是独立定义还是调用其他函数,它总是会指向window/global对象。

译者理解:可以看到,forEach中的function其实是无依无靠的,相当于一个匿名函数,因此它挂靠的就是window/global

1
2
3
4
5
6
const standAloneFunc = function () {
alert(this)
}

standAloneFunc()
// [object Window]

为什么呢?!
这里也被许多开发者所诟病,因此需要ES6箭头函数来补救。

再继续讲之前,先来看看ES5中是怎么补救的。

#1 使用中间变量来保存this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const bunny = {
name: 'Usagi',
tasks: ['transform', 'eat cake', 'blow kisses'],
showTasks: function() {
var _this = this
this.tasks.forEach(function(task) {
alert(_this.name + " wants to " + task);
})
}
}

bunny.showTasks()
// Usagi wants to transform
// Usagi wants to eat cake
// Usagi wants to blow kisses

#2 使用bind函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const bunny = {
name: 'Usagi',
tasks: ['transform', 'eat cake', 'blow kisses'],
showTasks: function() {
this.tasks.forEach(function(task) {
alert(this.name + " wants to " + task);
}.bind(this))
}
}

bunny.showTasks()
// Usagi wants to transform
// Usagi wants to eat cake
// Usagi wants to blow kisses

然后隆重介绍箭头函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const bunny = {
name: 'Usagi',
tasks: ['transform', 'eat cake', 'blow kisses'],
showTasks() {
this.tasks.forEach((task) => {
alert(this.name + " wants to " + task);
})
}
}

bunny.showTasks();
// Usagi wants to transform
// Usagi wants to eat cake
// Usagi wants to blow kisses

ES5函数中的this指向的是函数父级所在的作用域,而ES6中,箭头函数中的this指向的是当前所在的作用域,不会再更上一层。