如同我们所看到的,ES6 中引入来箭头函数,相比 ES5 来讲是最为直观而明显的特性。
在 ES6 之前,声明一个函数:
function add(a, b) {
return a + b;
}
add(1, 2); // 3
如果用箭头函数的形式写:
const add = (a, b) => a + b;
add(1, 2); // 3
计算圆面积的例子:
const square = (r) => {
const PI = 3.14;
return PI*r*r;
}
square(4);
形式上的改变仅仅是一部分,接下来关注一个很有用的特性:默认值。
默认值
在 ES6 之前,函数内给定参数的默认值,只能这样:
function add(a, b) {
console.log(arguments[0]);
a = a || 2000;
b = b || 333;
return a + b;
}
add(); // 2333
但是此方案遇到 boolean 为 false 的 js 值无法工作,例如:
add(0); // 2333
显然,结果错误。运算中 a 仍旧采用了默认值。
所以,当函数传参为 null, undefined, '', 0, -0, NaN
时,短路操作符 || 会给定默认值。
修订版成了这样:
function add(a, b) {
a = (typeof a !== 'undefined') ? a : 2000;
b = (typeof b !== 'undefined') ? b : 333;
return a + b;
}
add(0); // 333
而在 ES6 中,只需要给参数直接赋予默认值即可:
const add = (a = 2000, b = 333) => a + b;
add(); // 2333
add(0); // 333
默认值对 arguments 的影响
在 ES5 中:
function add(a, b) {
console.log(arguments.length);
console.log(a === arguments[0]);
console.log(b === arguments[1]);
a = 200;
b = 33;
console.log(a === arguments[0]);
console.log(b === arguments[1]);
}
add(1, 2);
// 2
// true
// true
// true
// true
如果在严格模式下运行,结果是这样的:
function add(a, b) {
'use strict';
console.log(arguments.length);
console.log(a === arguments[0]);
console.log(b === arguments[1]);
a = 200;
b = 33;
console.log(a === arguments[0]);
console.log(b === arguments[1]);
}
add(1, 2);
// 2
// true
// true
// false
// false
在 ES5 中的非严格模式下,更改参数值将会同步的更改 arguments 对象内的参数值,而在严格模式下不会更改。
对于 ES6 来说,无论是否在严格模式下,更改参数值的行为都不会同步更改 arguments 对象。
function add(a = 2000, b = 333) {
console.log(arguments.length);
console.log(a === arguments[0]);
console.log(b === arguments[1]);
a = 200;
b = 33;
console.log(a === arguments[0]);
console.log(b === arguments[1]);
}
add(0);
// 1
// true
// false
// false
// false
再来看个例子:
const add = (a = 2000, b = 333) => {
console.log(arguments.length);
console.log(a === arguments[0]);
console.log(b === arguments[1]);
a = 200;
b = 33;
console.log(a === arguments[0]);
console.log(b === arguments[1]);
}
add(0);
// Uncaught ReferenceError: arguments is not defined
另外需要注意的点是,箭头函数没有自己的 arguments 对象。但它可以访问外围函数的 arguments 对象:
function add(a = 2000, b = 333) {
return (() => arguments[0] + arguments[1])();
}
add(); // NaN
add(200, 33); // 233
this
在 ES6 的箭头函数中,this 值总是绑定到函数的定义:
const obj = {
name: 'Rainy',
say: function () {
setTimeout(() => {
console.log(`I'm ${this.name}`);
})
}
}
obj.say(); // I'm Rainy
而如果是普通函数,由于 setTimeout 函数内的 this 指向 window,所以找不到 name 值:
const obj = {
name: 'Rainy',
say: function () {
setTimeout(function () {
console.log(`I'm ${this.name}`);
})
}
}
obj.say(); // I'm
可以将箭头函数的该行为看作:
const obj = {
name: 'Rainy',
say: function () {
const self = this;
setTimeout(function () {
console.log(`I'm ${self.name}`);
})
}
}
obj.say(); // I'm Rainy
实际上这是由于箭头函数本身没有 this,其中的 this 实际上是外部函数的 this 绑定。
且箭头函数中的 this 值无法改变:
const obj = {
name: 'Rainy',
say: function () {
setTimeout((() => console.log(`I'm ${this.name}`)).bind({name: 'Null'}))
}
}
obj.say(); // I'm Rainy
而非箭头函数:
const obj = {
name: 'Rainy',
say: function () {
setTimeout((function () {console.log(`I'm ${this.name}`)}).bind({name: 'Null'}))
}
}
obj.say(); // I'm Null
也正因为如此,箭头函数无法作为构造函数,因为 this 值无法绑定至构造函数的实例。
参考
- 《深入理解 ES6》
- 《实战 ES2015》
- MDN
-EOF-
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。