ES6 引入了「箭头函数」(arrow function),以简化输入、节约时间。
但是,箭头函数不是用来取代 function
关键字的。如果掌握了 JavaScript 词法作用域、this
关键字、.call()
/.apply()
/.bind()
等原型方法,就比较容易理解箭头函数了。
语法
先看一下来自 MDN 的例子:
// example 1
([param] [, param]) => {
statements
}
// example 2
param => expression
上面的代码转换为 ES5 后等同于:
// example 1
function ([param] [, param]) {
statements
}
// example 2
function (param) {
return expression
}
example 1
中,ES6 省略了 function
关键字,并在参数后面添加了 =>
;example 2
中,ES6 缩减为一行,编写返回值的单行函数表达式时非常方便。
注意:箭头函数是匿名的
箭头函数始终是匿名的,使用箭头函数创建命名函数时需要将其赋值给变量。
// ES5
function doSomething() {
//...
}
// ES6
var doSomething = () => {
//...
}
语法:单行表达式
比如 Array.prototype.map
的使用:
// ES5
var numbers = [1,2,3,4,5];
var timesTwo = numbers.map(function (number) {
return number * 2;
});
console.log(timesTwo); // [2, 4, 6, 8, 10]
// ES6
var numbers = [1,2,3,4,5];
var timesTwo = numbers.map((number) => number * 2);
console.log(timesTwo); // [2, 4, 6, 8, 10]
语法:单参数函数
箭头函数提供了一个语法糖,允许只有一个参数时移除圆括号。
以上面的代码为例:
numbers.map((number) => number * 2);
可以省略 (number)
的括号:
numbers.map(number => number * 2);
这样简洁了一些,但建议始终保留括号,以方便维护(比如以后需要增加参数时)。
// we still rock with ES6
numbers.map((number) => number * 2);
箭头函数的词法作用域功能
ES5 中,一般使用 .bind()
之类的方法传递 this
,以改变函数的执行上下文,比如具有不同作用域的回调函数里。
function FooCtrl (FooService) {
this.foo = 'Hello';
FooService.doSomething(function (response) {
this.foo = response;
});
}
this.foo = response;
不会像预期的那样工作,因为 this
已经改变。使用 .bind(this)
可以达到预期的效果:
function FooCtrl (FooService) {
this.foo = 'Hello';
FooService.doSomething(function (response) {
this.foo = response;
}.bind(this));
}
或者使用一个局部的变量来保存 this
,尤其是在有多个嵌套上下文的时候(.bind()
执行起来非常慢)。使用 _this
来保存 this
引用:
function FooCtrl (FooService) {
var _this = this;
_this.foo = 'Hello';
FooService.doSomething(function (response) {
_this.foo = response;
});
}
现在有了更好的选择:箭头函数会自动绑定 this
为定义时所在的上下文,而不是执行时候的上下文。
function FooCtrl (FooService) {
this.foo = 'Hello';
FooService.doSomething((response) => { // woo, pretty
this.foo = response;
});
}
再简化一下:
function FooCtrl (FooService) {
this.foo = 'Hello';
FooService.doSomething((response) => this.foo = response);
}