Arrow Functions并不是什么新鲜玩意了,在Java 8和Apple Swift语言中也都有这种写法,只不过有的语言用单箭头(->),JS中用双箭头(=>),大同小异,单箭头更像C或者C++中的指针语法。ES6中描述Arrow Functions的章节在14.2,有兴趣的可以自己去看。
下面先看个简单的例子,然后在介绍其他特征:
let arr = [1, 2, 3];
let squares = arr.map(x => x * x);
console.log(squares);[1,4,9]
几种写法:
() => { } // 无参数
x => { } // 一个参数
(x, y) => {} // 多个参数
x => { return x * x } // 函数体
x => x * x // 如果函数体只有一条语句,并且是返回语句,可以简写,等同于上面的大括号写法
//如果函数体只有一条,并且是表达式,则可以省略大括号
let consoleFunc = x => console.log(x);
//如果函数体内是声明语句,则不能省略大括号
let throwFunc = x => {throw x };//如果去掉大括号,SyntaxError: expected expression, got keyword 'throw'
优先级:
箭头函数的优先级是很低的,仅比=号高一点:
console.log(typeof () => {}); //SyntaxError: invalid arrow-function arguments (parentheses around the arrow-function may help)
console.log(typeof (() => {})); //'function'
(() => {}) instanceof Function;//true
const value = () => foo();/*等同于*/const value = () => (foo())
//但是不等同于
const value = (() => foo)()
//如果函数体只有一条语句,并且返回的是个对象字面量,应该怎么写?
let f1 = x => { bar: 123 }
//还是
let f2 = x => ({ bar: 123 })
//答案是下面这种,但上面的写法同样不会报错!这里需要特殊注意,上面那种写法会被解析成复合语句,复合语句里面是个标签语句,然后跟着一个数值表达式。
//所以执行f1不会有什么结果,即返回undefined;执行f2则返回对象字面量
用箭头函数重写IIFE:
(function () {
console.log("IIFE");
}());
(() => {
console.log("Immediately Invoked Arrow Function");
})();
箭头函数参数解构语法:
[[1,2], [3,4]].map(([a,b]) => a + b);//[3,7]
[{x:3,y:4}, {x:5,y:6}].map(({x:XX,y}) => XX + y)//[7,11]
箭头函数参数默认值语法:
[1, undefined, 3].map((x='yes') => x);//[1, "yes",3]
//默认值+解构
[{x:3,y:4}, {x:5},{y:8}].map(({x:XX=0,y:y=0}) => XX + y);//[7,5,8]
[[1,2], [3,4],[5]].map(([a,b=0]) => a + b);//[3,7,5]
箭头函数体中的this:
在ES6中有两种this,一种是原有的动态绑定的this,另一种叫lexical this,就是这个this在词法解析的时候就确定了。而箭头函数属于后一种,ES6规范14.2的最后有这样一段NOTE:
An ArrowFunction does not define local bindings for arguments, super, this, or new.target. Any reference to arguments, super, this, or new.target within an ArrowFunction must resolve to a binding in a lexically enclosing environment. Typically this will be the Function Environment of an immediately enclosing function.
怎么理解上面这段话,看个简单的例子,你也许就明白了:
function Prefixer(prefix) {
this.prefix = prefix;
}
Prefixer.prototype.prefixArray = function (arr) {
return arr.map(function (x) {
return this.prefix + x;
});
};
//上面这段代码是不work的,因为在map的回调中this是动态绑定的,在非strict模式下,this是window。在严格模式下,将报错。
//下面用箭头函数解决问题
function Prefixer(prefix) {
this.prefix = prefix;
}
Prefixer.prototype.prefixArray = function (arr) {
return arr.map((x) => {
return this.prefix + x;
});
};
//箭头函数的this不是动态绑定的,是在词法分析阶段就确定了,map中的this就是prefixArray方法体this,即Prefixer实例
在看个用箭头函数解决事件绑定中的this:
var controller = {
prefix:"123",
makeRequest: function() {
document.getElementById("btn").addEventListener( "click", () => {
console.log(this.prefix);
}, false );
}
};
window.onload = function(){
controller.makeRequest();
}
箭头函数简化了函数的语法,并且解决了回调函数中的this问题,以后这种写法肯定会大范围普及,所以应该重点掌握。
*以上全部代码在Firefox 43下通过测试