ES6箭头函数语法糖真好吃,不过也有一些小陷阱噢~
噜啦啦噜啦啦噜啦噜啦咧~我萌一起来看看箭头函数の两种陷阱叭!!
箭头函数和对象字面量
箭头函数提供了更简短的语法,可以将函数编写为具有隐式返回值的 lambda 表达式。比如使用一个函数映射一些数组。使用常规函数可能会多出很多空行。
例如:
1 | const numbers = [1, 2, 3, 4]; |
用 lambda 样式的箭头函数来写的话,就会写成两行优雅、易读的代码:
1 | const numbers = [1, 2, 3, 4]; |
在这种用例中,箭头函数的表现符合预期,它将值本身相乘并返回到包含 [1, 4, 9, 16] 的新数组。
但如果你尝试映射到对象,那么结果可能和你想象的不一样了。例如,假设我们试图将数字映射到包含如下值的对象数组中:
1 | const numbers = [1, 2, 3, 4]; |
这里的结果实际上是一个包含未定义值的数组。虽然看起来在这里返回一个对象,但是解释器看到的东西完全不一样。花括号被解释为箭头函数的块作用域,而值语句最后实际上成为了标签。在解释器眼里,它看起来是这样的:
1 | const numbers = [1, 2, 3, 4]; |
解决方法在这里。只需要将对象包装在括号中,就可以将它变成一个表达式而不是一个块语句,如下所示:
1 | const numbers = [1, 2, 3, 4]; |
这会计算出一个包含对象数组的数组,该对象数组具有预期的值。
箭头函数和绑定
箭头函数没有自己的 this 绑定,即它们的 this 值和封闭词法作用域的 this 值是一样的。
箭头函数的this 绑定很可能与你原本所想的不一样。例如:
1 | let calculator = { |
我们希望这里的 this 绑定为此处的 calculator 对象,但实际上 this 绑定最后要么是未定义,要么是全局对象,具体取决于代码是否在严格模式下运行。这是因为这里最接近的词汇作用域是全局作用域。在严格模式下这是未定义的。(否则,它会是浏览器的窗口对象(或 Node.js 兼容环境中的过程对象。
常规函数具有 this 绑定。在对象上调用时,this 将指向该对象,因此常规函数依然是获得成员函数的正确途径:
1 | let calculator = { |
另外,由于箭头函数没有 this 绑定,因此无法使用Function.prototype.call、Function.prototype.bind 和 Function.prototype.apply。声明箭头函数后,this 绑定设置为固定,无法更改。
因此,下面的示例将遇到与之前类似的问题:当调用 adder 的 add 函数时,this 绑定又成了全局对象,尽管我们尝试使用 Function.prototype.call 覆盖它:
1 | const adder = { |
什么时候IDE才能学会自己写代码 :)
参考链接:
Lesser-Known JavaScript Hazards
ECMAScript® 2018 Language Specification
Author: 樱花雨