你所提到的
,
是逗号运算符 (
MDN entry)。
这个运算符来自C语言,其用例通常是声明多个变量(
var i, j, k
)和特定宏定义(这些宏定义非常麻烦)。
大多数现代语言为了更高级的抽象性而放弃了使用这个运算符。
但即使我们忽略历史,我认为最佳实践的主要目标之一应该是
可读性属性。目标肯定不是为了节省几个按键。
现在来比较一下:
let doubleSum;
[1,2,3,4,5].reduce((sum, element) => (doubleSum=sum+sum, doubleSum+element));
并且
[1,2,3,4,5].reduce((sum, element) =>
{
const doubleSum = sum + sum;
return doubleSum + element;
});
其中一个示例将doubleSum
声明为闭合变量,用于所有reduce
迭代,而另一个则将doubleSum
声明为每次迭代的本地变量。你认为哪个更好地表达了意图?哪一个更容易重构而不担心破坏某些奇怪的情况?
在日志记录示例中,这并不是很清楚。然而,通常认为将每个副作用(如记录消息)放入单独的语句中(以;
结尾的行)是一种良好的实践。
想象一下:
someArray.map((element) => (console.log(element), doSomething(element)));
然而,由于某种原因,doSomething
没有按照您的期望工作。让我们添加一些日志记录:
let intermediate;
someArray.map((element) => (
console.log(element),
intermediate = doSometing(element),
console.log(intermediate),
intermediate));
我们又遇到了与“intermediate”有关的奇怪作用域问题。这个更改可能并不容易 - 你想在“map”回调中做一些事情,但实际上你必须在其范围之外创建一个变量才能做到这一点。现在想象一下,映射回调的复杂性会增加,需要几个这样的绑定变量。或者可能有更多的if/else分支和变量。然后,你可能想将其提取到一个单独的函数中:现在你需要再次考虑所有绑定变量。
那么使用块如何呢?
someArray.map((element) =>
{
console.log(element);
doSomething(element);
});
变成
someArray.map((element) =>
{
console.log(element);
const intermediate = doSometing(element);
console.log(intermediate);
return intermediate;
});
现在,我们只需要编辑地图回调的内部块,改变变得更容易做到和理解。引入更多变量?没问题,它们都留在回调函数中。将回调函数提取为单独的函数?也没有问题。这段代码的意图很清楚。