javascript - 减少函数中的变异累加器是否被认为是不好的做法?
问题描述
我是函数式编程的新手,我正在尝试重写一些代码以使其更具功能性来掌握这些概念。刚才我发现了Array.reduce()
函数并用它来创建组合数组的对象(在那之前我使用过for
循环)。但是,我不确定。看看这段代码:
const sortedCombinations = combinations.reduce(
(accum, comb) => {
if(accum[comb.strength]) {
accum[comb.strength].push(comb);
} else {
accum[comb.strength] = [comb];
}
return accum;
},
{}
);
显然,这个函数改变了它的参数accum
,所以它不被认为是纯的。另一方面,如果我理解正确,reduce 函数会从每次迭代中丢弃累加器,并且在调用回调函数后不使用它。不过,它不是一个纯函数。我可以这样重写它:
const sortedCombinations = combinations.reduce(
(accum, comb) => {
const tempAccum = Object.assign({}, accum);
if(tempAccum[comb.strength]) {
tempAccum[comb.strength].push(comb);
} else {
tempAccum[comb.strength] = [comb];
}
return tempAccum;
},
{}
);
现在,在我的理解中,这个函数被认为是纯粹的。但是,它每次迭代都会创建一个新对象,这会消耗一些时间,而且显然还需要内存。
所以问题是:哪种变体更好,为什么?纯度真的那么重要,以至于我应该牺牲性能和内存来实现它吗?或者也许我错过了一些东西,还有更好的选择?
解决方案
TL; DR:如果您拥有蓄电池,则不是。
在 JavaScript 中使用扩展运算符来创建漂亮的单行归约函数是很常见的。开发人员经常声称它还使他们的功能在过程中变得纯粹。
const foo = xs => xs.reduce((acc, x) => ({...acc, [x.a]: x}), {});
//------------------------------------------------------------^
// (initial acc value)
但是让我们想一想……如果你发生了变异,可能会出什么问题acc
?例如,
const foo = xs => xs.reduce((acc, x) => {
acc[x.a] = x;
return acc;
}, {});
绝对没有。
的初始值acc
是动态创建的空文字对象。在这一点上,使用扩展运算符只是一种“修饰”的选择。这两个函数都是纯函数。
不变性是一种特性,而不是过程本身。这意味着克隆数据以实现不变性很可能是一种幼稚且低效的方法。大多数人忘记了传播运算符无论如何只做一个浅克隆!
我不久前写了这篇文章,我声称变异和函数式编程不必相互排斥,并且我还表明使用扩展运算符并不是一个简单的选择。
推荐阅读
- java - 按集合中的元素查找
- nginx-reverse-proxy - ESXi vCenter 7.0 NginX 反向代理问题
- javascript - 如何从异步函数返回值并将其声明为全局
- android - Vk Api 请求在 android 应用程序中不起作用
- android - 在 android 上使用 opencv 启动 2 个摄像头
- .htaccess - 用于指向自定义域的 DNS CNAME 设置(多租户 SaaS)
- visual-studio - 如何复制我的 Visual Basic 程序(源代码和表单)
- html - juypter 和 html markdown 单元格有问题
- c - 如何从/向初始化结构的函数传递结构?
- python - ValueError:找到昏暗 4 的数组。使用 KNN 预测数字时,估计器预期 <= 2