13.5 语法陷阱
有几个语法相关的细节问题可能会给你带来麻烦。
13.5.1 箭头函数绑得非常松散
箭头函数绑得非常松散。原因是希望每一个能在表达式体中出现的表达式都“紧紧结合在一起”,但是实际上另一个表达式比箭头函数结合性更高。
结果,在其它某些地方,经常不得不将箭头函数包裹在小括号中。例如:
console.log(typeof () => {}); // SyntaxError
console.log(typeof (() => {})); // OK
另一方面,可以使用 typeof
作为一个表达式体,不用放在大括号中:
const f = x => typeof x;
13.5.2 立即调用的箭头函数
还记得立即调用函数表达式( IIFEs )吗?在 ECMAScript 5 中用于模拟块级作用域和值返回块,看起来像下面这样:
(function () { // open IIFE
// inside IIFE
}()); // close IIFE
如果使用立即调用的箭头函数( IIAF ),可以省掉几个字符:
(() => {
return 123
})();
和 IIFEs
类似,应该在 IIAFs 结尾加上分好(或者使用一个等价的措施),以避免两个连续的 IIAFs 被解释成一个函数调用(第一个是函数,第二个是参数)。
即便 IIAF 有一个块体,也必须使用小括号包裹起来,因为它结合松散,不能(直接地)做函数调用。注意小括号一定是包住了箭头函数。使用 IIFEs 的话,你有一个选择:用小括号要么包住整个语句,要么包住函数表达式。
就像上节提到的,箭头函数结合松散,这对于表达式体很有用,比如你想让这种表达式:
const value = () => foo()
解释成这样:
const value = () => (foo())
而不是这样:
const value = (() => foo)()
本章关于可调用实体的那一节有更多关于在 ES6 中使用 IIFEs 和 IIFAs 的信息。
13.5.4 不能用语句作为表达式体
13.5.4.1 表达式与语句
快速复习(参阅《 Speaking JavaScript 》获取更多相关信息):
表达式产生(执行得到)值。例子:
3 + 4
foo(7)
'abc'.length
语句完成功能。例子:
while (true) { ··· }
return 123;
大多数表达式可以被用作语句,简单地将它们放在语句的位置上:
function bar() {
3 + 4;
foo(7);
'abc'.length;
}
13.5.4.2 箭头函数体
如果箭头函数体是一个表达式,那么就可以不需要括号了:
asyncFunc.then(x => console.log(x));
但是,语句一定要放在括号里面:
asyncFunc.catch(x => { throw x });
13.5.5 返回一个对象字面量
有一个块体而不是一个表达式体意味着如果你想让表达式体是一个对象字面量,就必须将其放在括号中。
箭头函数体是一个带有 bar
的标签和 123
的表达式语句。
let f = x => { bar: 123 }
箭头函数体是一个表达式,一个对象字面量:
let f = x => ({ bar: 123 })