lambda函数即匿名函数,在ES6发布之前,我们通常会这样写匿名函数
var selected = allJobs.filter(function (job) {
return job.isSelected();
});
ES6中引入了一种编写函数的新语法
var selected = allJobs.filter(job => job.isSelected());
它的语法非常简单:标识符=>表达式。如果要写一个接受多重参数(也可能没有参数,或者是不定参数、默认参数、参数解构)的函数,你需要用小括号包裹参数list。
// ES5
var total = values.reduce(function (a, b) {
return a + b;
}, 0);
// ES6
var total = values.reduce((a, b) => a + b, 0);
除表达式外,箭头函数还可以包含一个块语句。
// ES5
$("#confetti-btn").click(function (event) {
playTrumpet();
fireConfettiCannon();
});
// ES6
$("#confetti-btn").click(event => {
playTrumpet();
fireConfettiCannon();
});
注意,使用了块语句的箭头函数不会自动返回值,你需要使用return语句将所需值返回。
小提示:当使用箭头函数创建普通对象时,你总是需要将对象包裹在小括号里。
// 为puppies中的每一个小狗创建一个新的空对象
var chewToys = puppies.map(puppy => {}); // 这样写会报Bug!
var chewToys = puppies.map(puppy => ({})); //用小括号包裹空对象就可以了
不幸的是,一个空对象{}和一个空的块{}看起来完全一样。ES6中的规则是,紧随箭头的{被解析为块的开始,而不是对象的开始。因此,puppy => {}这段代码就被解析为没有任何行为并返回undefined的箭头函数。
绑定 this
在箭头函数出现之前,每个新定义的函数都有其自己的 this 值.
function Person() {
// 构造函数 Person() 定义的 `this` 就是新实例对象自己
this.age = 0;
setInterval(function growUp() {
// 在非严格模式下,growUp() 函数定义了其内部的 `this`
// 为全局对象, 不同于构造函数Person()的定义的 `this`
this.age++;
}, 1000);
}
var p = new Person();
在 ECMAScript 3/5 中,这个问题可以通过新增一个变量来指向期望的 this 对象,然后将该变量放到闭包中来解决。
function Person() {
var self = this; // 也有人选择使用 `that` 而非 `self`.
// 只要保证一致就好.
self.age = 0;
setInterval(function growUp() {
// 回调里面的 `self` 变量就指向了期望的那个对象了
self.age++;
}, 1000);
}
箭头函数的函数体内的this对象,是在定义时绑定的,所谓的定义时候绑定,就是this是继承自父执行上下文,而不是使用时所在的对象,是固定值。例如
var x=11;
var obj={
x:22,
say:()=>{
console.log(this.x);
}
}
obj.say();
//输出的值为11
这里的箭头函数中的this.x,箭头函数本身与say平级以key:value的形式,也就是箭头函数本身所在的对象为obj,而obj的父执行上下文就是window,因此这里的this.x实际上表示的是window.x,因此输出的是11。箭头函数会捕获其父执行上下文的 this 值,作为自己的 this 值,因此下面的代码将如期运行。
function Person(){
this.age = 0;
setInterval(() => {
this.age++; // |this| 正确地指向了 person 对象
}, 1000);
}
var p = new Person();
简单对象(非函数)是没有执行上下文的,箭头函数中,this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。正是因为它没有this,所以也就不能用作构造函数。
箭头函数转成 ES5 的代码如下。
// ES6
function foo() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
// ES5
function foo() {
var _this = this;
setTimeout(function () {
console.log('id:', _this.id);
}, 100);
}
上面代码中,转换后的ES5版本清楚地说明了,箭头函数里面根本没有自己的this,而是引用外层的this。
请问下面的代码之中有几个this?
function foo() {
return () => {
return () => {
return () => {
console.log('id:', this.id);
};
};
};
}
var f = foo.call({id: 1});
var t1 = f.call({id: 2})()(); // id: 1
var t2 = f().call({id: 3})(); // id: 1
var t3 = f()().call({id: 4}); // id: 1
上面代码之中,只有一个this,就是函数foo的this,所以t1、t2、t3都输出同样的结果。因为所有的内层函数都是箭头函数,都没有自己的this,它们的this其实都是最外层foo函数的this。
使用 call 或 apply 调用时的this值?
call()和apply()的第一个参数都是要调用的函数的对象,在函数体内这一参数是关键字this的值,剩余参数是传递给要调用的函数的值。由于箭头函数没有自己的this,所以当然也就不能用call()、apply()、bind()这些方法去改变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)); // 输出 2
console.log(adder.addThruCall(1)); // 仍然输出 2(而不是3)
不绑定 arguments
箭头函数不会在其内部暴露出 arguments 对象: arguments.length, arguments[0], arguments[1] 等等,都不会指向箭头函数的 arguments,而是指向了箭头函数所在作用域的一个名为 arguments 的值(如果有的话,否则,就是 undefined)。
var arguments = 42;
var arr = () => arguments;
arr(); // 42
function foo() {
var f = () => arguments[0]; // foo's implicit arguments binding
return f(2);
}
foo(1); // 1 (不是2)
箭头函数没有自己的 arguments 对象,不过在大多数情形下,rest参数可以给出一个解决方案:
function foo() {
var f = (...args) => args[0];
return f(2);
}
foo(1); // 2
另外要注意,箭头函数不能用作构造器,和 new 一起用就会抛出错误。箭头函数在参数和箭头之间不能换行哦!
参考链接:
http://www.infoq.com/cn/articles/es6-in-depth-arrow-functions
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Arrow_functions