箭头函数是使用=>
语法对函数定义的简写。它们在语法上类似于 C#,Java 8 和 CoffeeScript 中的相关特性。它们支持表达式(Expression bodies)和函数体(Statement bodies)。与函数不同,箭头函数与其上下文代码共享相同的词法this
(注:箭头函数并没有自己的this,它的this是派生而来的,根据“词法作用域”派生而来)。如果箭头函数在另一个函数体内,它共享其父函数的 arguments
变量。
// 使用表达式(Expression bodies) var odds = evens.map(v => v + 1); var nums = evens.map((v, i) => v + i); // 使用函数体(Statement bodies) nums.forEach(v => { if (v % 5 === 0) fives.push(v); }); // 词法`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 (let number of arguments) { numbers.push(number * number); } return numbers; }; return example(); } square(2, 4, 7.5, 8, 11.5, 21); // returns: [4, 16, 56.25, 64, 132.25, 441]
更多信息:
注:
用Babel转译一下上面的代码,结果:
"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); }); // Lexical this var bob = { _name: "Bob", _friends: [], printFriends: function printFriends() { var _this = this; this._friends.forEach(function (f) { return console.log(_this._name + " knows " + f); }); } }; // Lexical 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) { var number = _step.value; numbers.push(number * number); } } 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, 16, 56.25, 64, 132.25, 441]
值得注意的是,这里的this
:
// Lexical this var bob = { _name: "Bob", _friends: [], printFriends: function printFriends() { var _this = this; this._friends.forEach(function (f) { return console.log(_this._name + " knows " + f); }); } };
从转译结果的printFriends
函数中var _this = this;
可以看出,_this
指向bob
对象。
比较一下下面两段代码:
var bob = { _name: "Bob", _friends: [""], printFriends() { this._friends.forEach(f => console.log(this._name + " knows " + f)); } }; bob.printFriends();// Bob knows
var bob = { _name: "Bob", _friends: [""], printFriends() { this._friends.forEach(function (f) { return console.log(this._name + " knows " + f); }); } }; bob.printFriends();// undefined knows
原因很简单:箭头函数与其上下文代码共享相同的词法this
,所以this
指向bob
对象,第2段代码forEach
中的匿名函数上下文是window
对象,所以this
指向window
对象。
题外话,要想修复第2段代码的问题,除了Babel提供的转译外,还可以使用 ES5 的 bind() :
var bob = { _name: "Bob", _friends: [""], printFriends() { this._friends.forEach(function (f) { return console.log(this._name + " knows " + f); }.bind(this)); } }; bob.printFriends();// Bob knows
bind() 最简单的用法是使函数的上下文指向其参数。(https://www.7psus5.com/archives/5611)。
学习了,很不错