Arrow functions
Arrow functions
箭头函数表达式
的语法比函数表达式更短,并且不绑定自己的this,arguments,super或 new.target。这些函数表达式最适合用于非方法函数,并且它们不能用作构造函数。
语法
基础语法
(param1, param2, …, paramN) => { statements }
(param1, param2, …, paramN) => expression
// equivalent to: (param1, param2, …, paramN) => { return expression; }
// Parentheses are optional when there's only one parameter name:
(singleParam) => { statements }
singleParam => { statements }
// A function with no parameters should be written with a pair of parentheses.
() => { statements }
高级语法
// Parenthesize the body of function to return an object literal expression:
params => {foo: bar})
// Rest parameters and default parameters are supported
(param1, param2, ...rest) => { statements }
(param1 = defaultValue1, param2, …, paramN = defaultValueN) => { statements }
// Destructuring within the parameter list is also supported
let f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
f(
// 6
描述
参考 "ES6 In Depth: Arrow functions" on hacks.mozilla.org
.
引入箭头函数有两个方面的作用:更简短的函数并且不绑定this
。
更短的函数
var materials = [
'Hydrogen',
'Helium',
'Lithium',
'Beryllium'
];
materials.map(function(material) {
return material.length;
} // [8, 6, 7, 9]
materials.map((material) => {
return material.length;
} // [8, 6, 7, 9]
materials.map(material => material.length // [8, 6, 7, 9]
不绑定this
在箭头函数出现之前,每个新定义的函数都有它自己的 this
值(在构造函数的情况下是一个新对象,在严格模式的函数调用中为 undefined,如果该函数被称为“对象方法”则为基础对象等)。This
被证明是令人厌烦的面向对象风格的编程。
function Person() {
// The Person() constructor defines `this` as an instance of itself.
this.age = 0;
setInterval(function growUp() {
// In non-strict mode, the growUp() function defines `this`
// as the global object, which is different from the `this`
// defined by the Person() constructor.
this.age++;
}, 1000
}
var p = new Person(
在ECMAScript 3/5中,通过将this
值分配给封闭的变量,可以解决this
问题。
function Person() {
var that = this;
that.age = 0;
setInterval(function growUp() {
// The callback refers to the `that` variable of which
// the value is the expected object.
that.age++;
}, 1000
}
或者,可以创建绑定函数,以便将预先分配的this
值传递到绑定的目标函数(上述示例中的growUp()
函数)。
箭头函数不会创建自己的this
;它使用封闭执行上下文的this
值。因此,在下面的代码中,传递给setInterval
的函数内的this
与封闭函数中的this
值相同:
function Person(){
this.age = 0;
setInterval(() => {
this.age++; // |this| properly refers to the person object
}, 1000
}
var p = new Person(
与严格模式的关系
鉴于 this
是词法层面上的,严格模式中与 this
相关的规则都将被忽略。
var f = () => { 'use strict'; return this; };
f() === window; // or the global object
严格模式的其他规则依然不变.
通过 call 或 apply 调用
由于 this
已经在词法层面完成了绑定,通过 call()
或
apply()
方法调用一个函数时,只是传入了参数而已,对 this
并没有什么影响:
var adder = {
base: 1,
add: function(a) {
var f = v => v + this.base;
return f(a
},
addThruCall: function(a) {
var f = v => v + this.base;
var b = {
base: 2
};
return f.call(b, a
}
};
console.log(adder.add(1) // This would log to 2
console.log(adder.addThruCall(1) // This would log to 2 still
不绑定arguments
箭头函数不绑定Arguments 对象。因此,在本示例中,参数只是在封闭范围内引用相同的名称:
var arguments = 42;
var arr = () => arguments;
arr( // 42
function foo() {
var f = (i) => arguments[0] + i; // foo's implicit arguments binding
return f(2
}
foo(1 // 3
在大多数情况下,使用剩余参数是使用arguments
对象的好选择。
function foo() {
var f = (...args) => args[0];
return f(2
}
foo( // 2
像方法一样使用箭头函数
如上所述,箭头函数表达式对非方法函数是最合适的。让我们看看当我们试着把它们作为方法时发生了什么。
'use strict';
var obj = {
i: 10,
b: () => console.log(this.i, this),
c: function() {
console.log(this.i, this
}
}
obj.b( // prints undefined, Window {...} (or the global object)
obj.c( // prints 10, Object {...}
箭头函数没有定义this绑定。另一个涉及Object.defineProperty()
的示例:
'use strict';
var obj = {
a: 10
};
Object.defineProperty(obj, 'b', {
get: () => {
console.log(this.a, typeof this.a, this
return this.a + 10; // represents global object 'Window', therefore 'this.a' returns 'undefined'
}
}
使用 new 操作符
箭头函数不能用作构造器,和new
一起用会抛出错误。
var Foo = () => {};
var foo = new Foo( // TypeError: Foo is not a constructor
使用prototype属性
箭头函数没有prototype
属性。
var Foo = () => {};
console.log(Foo.prototype // undefined
使用 yield 关键字
yield
关键字通常不能在箭头函数中使用(除非是嵌套在允许使用的函数内)。因此,箭头函数不能用作生成器。
函数体
箭头函数可以有一个“简写体”或常见的“块体”。
在一个简写体中,只需要一个表达式,并附加一个隐式的返回值。在块体中,必须使用明确的return
语句。
var func = x => x * x;
// concise syntax, implied "return"
var func = (x, y) => { return x + y; };
// with block body, explicit "return" needed
返回对象字面量
记住用params => {object:literal}这种简单的语法返回对象字面量是行不通的。
var func = () => { foo: 1 };
// Calling func() returns undefined!
var func = () => { foo: function() {} };
// SyntaxError: function statement requires a name
这是因为花括号({}
)里面的代码被解析为一系列语句(即 foo
被认为是一个标签,而非对象字面量的组成部分)。
所以,记得用圆括号把对象字面量包起来:
var func = () => {foo: 1}
换行
箭头函数在参数和箭头之间不能换行。
var func = ()
=> 1;
// SyntaxError: expected expression, got '=>'
解析顺序
虽然箭头函数中的箭头不是运算符,但箭头函数具有与常规函数不同的特殊运算符优先级解析规则。
let callback;
callback = callback || function() {}; // ok
callback = callback || () => {};
// SyntaxError: invalid arrow-function arguments
callback = callback || (() => {} // ok
更多示例
// An empty arrow function returns undefined
let empty = () => {};
(() => 'foobar')(
// Returns "foobar"
// (this is an Immediately Invoked Function Expression
// see 'IIFE' in glossary)
var simple = a => a > 15 ? 15 : a;
simple(16 // 15
simple(10 // 10
let max = (a, b) => a > b ? a : b;
// Easy array filtering, mapping, ...
var arr = [5, 6, 13, 0, 1, 18, 23];
var sum = arr.reduce((a, b) => a + b
// 66
var even = arr.filter(v => v % 2 == 0
// [6, 0, 18]
var double = arr.map(v => v * 2
// [10, 12, 26, 0, 2, 36, 46]
// More concise promise chains
promise.then(a => {
// ...
}).then(b => {
// ...
}
// Parameterless arrow functions that are visually easier to parse
setTimeout( () => {
console.log('I happen sooner'
setTimeout( () => {
// deeper code
console.log('I happen later'
}, 1
}, 1
规范
Specification | Status | Comment |
---|---|---|
ECMAScript 2015 (6th Edition, ECMA-262)The definition of 'Arrow Function Definitions' in that specification. | Standard | Initial definition. |
ECMAScript Latest Draft (ECMA-262)The definition of 'Arrow Function Definitions' in that specification. | Living Standard | |
浏览器兼容性
Feature | Chrome | Edge | Firefox (Gecko) | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|---|
Basic support | 45.0 | (Yes) | 22.0 (22.0) | No support | 32 | 10.0 |
Trailing comma in parameters | ? | ? | 52.0 (52.0) | ? | ? | ? |
Feature | Android | Android Webview | Edge | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile | Chrome for Android |
---|---|---|---|---|---|---|---|---|
Basic support | No support | 45.0 | (Yes) | 22.0 (22.0) | No support | No support | 10.0 | 45.0 |
Trailing comma in parameters | ? | ? | ? | 52.0 (52.0) | ? | ? | ? | ? |
Firefox特定的笔记
- Firefox中的箭头函数的初始实现使得它们自动严格。这已经改变为Firefox 24。采用
"use strict"
;它现在需要的。
- 箭头函数在语义上与Firefox 3中添加的非标准表达式闭包不同(细节:JavaScript 1.8),是由于表达式闭包不会在
this
词法上绑定。
- 在Firefox 39之前,在箭头函数参数之后不正确地允许行结束符(\n)。这已经被修正,以符合ES2015规范和像() \n => {}现在将在这个和以后的版本的代码中抛出一个SyntaxError。