ES6箭头函数语法糖真好吃,不过也有一些小陷阱噢~

噜啦啦噜啦啦噜啦噜啦咧~我萌一起来看看箭头函数の两种陷阱叭!!

箭头函数和对象字面量

箭头函数提供了更简短的语法,可以将函数编写为具有隐式返回值的 lambda 表达式。比如使用一个函数映射一些数组。使用常规函数可能会多出很多空行。

例如:

1
2
3
4
const numbers = [1, 2, 3, 4];
numbers.map(function(n) {
return n * n;
});

用 lambda 样式的箭头函数来写的话,就会写成两行优雅、易读的代码:

1
2
const numbers = [1, 2, 3, 4];
numbers.map(n => n * n);

在这种用例中,箭头函数的表现符合预期,它将值本身相乘并返回到包含 [1, 4, 9, 16] 的新数组。

如果你尝试映射到对象,那么结果可能和你想象的不一样了。例如,假设我们试图将数字映射到包含如下值的对象数组中:

1
2
const numbers = [1, 2, 3, 4];
numbers.map(n => { value: n });

这里的结果实际上是一个包含未定义值的数组。虽然看起来在这里返回一个对象,但是解释器看到的东西完全不一样。花括号被解释为箭头函数的块作用域,而值语句最后实际上成为了标签。在解释器眼里,它看起来是这样的

1
2
3
4
5
6
const numbers = [1, 2, 3, 4];
numbers.map(function (n) {
value:
n
return;
});

解决方法在这里。只需要将对象包装在括号中,就可以将它变成一个表达式而不是一个块语句,如下所示:

1
2
const numbers = [1, 2, 3, 4];
numbers.map(n => ({ value: n }));

这会计算出一个包含对象数组的数组,该对象数组具有预期的值。

箭头函数和绑定

箭头函数没有自己的 this 绑定,即它们的 this 值和封闭词法作用域的 this 值是一样的。

箭头函数的this 绑定很可能与你原本所想的不一样。例如:

1
2
3
4
5
6
7
8
let calculator = {
value: 0,
add: (values) => {
this.value = values.reduce((a, v) => a + v, this.value);
},
};
calculator.add([1, 2, 3]);
console.log(calculator.value); // 0

我们希望这里的 this 绑定为此处的 calculator 对象,但实际上 this 绑定最后要么是未定义,要么是全局对象,具体取决于代码是否在严格模式下运行。这是因为这里最接近的词汇作用域是全局作用域。在严格模式下这是未定义的。(否则,它会是浏览器的窗口对象(或 Node.js 兼容环境中的过程对象。

常规函数具有 this 绑定。在对象上调用时,this 将指向该对象,因此常规函数依然是获得成员函数的正确途径:

1
2
3
4
5
6
7
8
let calculator = {
    value0,
    add(values) {
        this.value = values.reduce((a, v) => a + v, this.value);
    },
};
calculator.add([1, 2, 3]);
console.log(calculator.value);  // 6

另外,由于箭头函数没有 this 绑定,因此无法使用Function.prototype.call、Function.prototype.bind 和 Function.prototype.apply。声明箭头函数后,this 绑定设置为固定,无法更改。

因此,下面的示例将遇到与之前类似的问题:当调用 adder 的 add 函数时,this 绑定又成了全局对象,尽管我们尝试使用 Function.prototype.call 覆盖它:

1
2
3
4
5
6
7
8
9
const adder = {
add: (values) => {
this.value = values.reduce((a, v) => a + v, this.value);
},
};
let calculator = {
value: 0
};
adder.add.call(calculator, [1, 2, 3]); // undefined

什么时候IDE才能学会自己写代码 :)

参考链接:

Lesser-Known JavaScript Hazards

ECMAScript® 2018 Language Specification

本文采用CC-BY-SA-3.0协议,转载请注明出处
Author: 樱花雨