ES6学习笔记1:箭头函数和词法作用域this

箭头函数和词法作用域this

箭头函数(Arrows)允许了一种全新的更简便的函数定义和使用方式,其类似于Java8中的lambda表达式,也分为表达式(Expression Body,求值代码)和语句(Statement Body,一系列可执行代码)。他与一般的JS函数有些区别,其中最重要的区别就是词法作用域this(Lexical this)和词法作用域arguments(Lexical arguments)属性,这表示该函数与父级函数作用域共享同一this指针和arguments参数。

箭头函数

ES6代码

1
2
3
4
5
6
7
8
// 表达式箭头函数
var odds = evens.map(v => v + 1);
var nums = evens.map((v, i) => v + i);
// 语句箭头函数
nums.forEach(v => {
if (v % 5 === 0)
fives.push(v);
});

使用Babel编译后的ES5代码

1
2
3
4
5
6
7
8
9
10
11
12
"use strict";
// Expression bodies
var odds = evens.map(function (v) {
return v + 1;
});
var nums = evens.map(function (v, i) {
return v + i;
});
// Statement bodies
nums.forEach(function (v) {
if (v % 5 === 0) fives.push(v);
});

首先Babel编译后的ES5代码都是在严格模式下的ES5代码,其次可以看出,上述例子中的箭头函数相当于ES5中的匿名函数。

词法作用域this和词法作用域arguments

有一定JavaScript的经验的开发人员应该知道,和大多数编程语言一样,JS也是基于词法作用域的编程语言,这表示JS的作用域在预编译过程中就已经确定了变量的作用域,在ES5中,JS是不存在块级作用域而只存在函数作用域的,但在ES6中引入了块级作用域(后续文章中还会提到)。箭头函数虽然称为函数,但其不存在『属于自己的』独立的this和arguments,也就是说其使用的是外部作用域中的this和arguments,这在ES6中被称为词法作用域this和词法作用域arguments。

ES6代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 词法作用域this
var bob = {
_name: "Bob",
_friends: [],
printFriends() {
this._friends.forEach(f =>
console.log(this._name + " knows " + f));
}
};
// 词法作用域arguments
function square() {
let example = () => {
let numbers = [];
for (number of arguments) {
numbers.push(number * 2);
}
return numbers;
};
return example();
}
square(2, 4, 7.5, 8, 11.5, 21); // returns: [4, 8, 15, 16, 23, 42]

使用Babel编译后的ES5代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
"use strict";
// 词法作用域this
var bob = {
_name: "Bob",
_friends: [],
printFriends: function printFriends() {
var _this = this;
this._friends.forEach(function (f) {
return console.log(_this._name + " knows " + f);
});
}
};
// 词法作用域arguments
function square() {
var _arguments = arguments;
var example = function example() {
var numbers = [];
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = _arguments[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
number = _step.value;
numbers.push(number * 2);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return numbers;
};
return example();
}
square(2, 4, 7.5, 8, 11.5, 21); // returns: [4, 8, 15, 16, 23, 42]

可以看出,在ES6的箭头函数对应的ES5代码中,相当于外部函数作用域中的this和arguments被保存了起来并在内部匿名函数(对应ES6中的箭头函数)中被当做this和arguments(即上述代码中的_this和_arguments)使用。

知识点总结

  1. 箭头函数的两种写法;
  2. 箭头函数中的词法作用域this和词法作用域arguments(即作用域范围同父作用域)。

参考

  1. BabelJS - Learn ES2015