我应该避免在 reduce 中使用 object spread 吗?
Should I avoid using object spread in reduce?
给定以下示例:
// option 1
items.reduce((values, item) => ({
...values,
[item.id]: item.name
}), {})
// option 2
items.reduce((values, item) => {
values[item.id] = item.name;
return values;
}, {});
在这种情况下,使用对象传播语法是否有赞成或反对的最佳做法?
在第一个代码中,您要为 .reduce
的每次迭代创建一个新对象。在某些引擎中,这可能比您的第二个代码效率稍低,后者仅创建一个对象。 (也就是说,效率很少很重要;在大多数情况下,代码清晰度更为重要)。
但是,对于这种情况,从数组创建对象时有一个更合适的方法,它避免了 reduce
:
稍微笨拙的语法
const output = Object.fromEntries(
items.map(item => [item.id, item])
);
const items = [
{ id: 5, val: 5 },
{ id: 10, val: 10 },
{ id: 15, val: 15 },
];
const output = Object.fromEntries(
items.map(item => [item.id, item])
);
console.log(output);
也就是说,请记住 Object.fromEntries
是一项相对较新的功能,因此如果这是面向 public 的网站,请确保包含一个 polyfill。
...values
每次都会创建数组的浅表副本,如果数组很大,这可能会很昂贵。另一方面,在累加器上设置 属性 更有效。话虽如此,您可以确定您的数组肯定足够小,以至于您更喜欢简洁的展开语法。
出于性能原因,选项 2 显然更可取:
- 选项 1 在 O(n²) 时间内运行,因为扩展语法在每次迭代时复制 O(n) 个属性。选项 2 在 O(n) 时间内运行。
- 选项 1 创建 O(n²) 垃圾,因为它在每次迭代时创建大小为 O(n) 的垃圾对象。选项 2 不会产生垃圾。
就是说,在大多数情况下你应该只用一个普通的旧 for
循环来写这个:
let result = {};
for(let item of items) {
result[item.id] = item.name;
}
用for
循环也不错,而且代码比题中的两个选项更具可读性。选项 2 可能看起来更像是函数式编程风格,但如果您使用变异来实现您想要的结果,那么您并不是真正在进行函数式编程。
有关为什么选项 1 是反模式的更深入讨论,请参阅 this article。
给定以下示例:
// option 1
items.reduce((values, item) => ({
...values,
[item.id]: item.name
}), {})
// option 2
items.reduce((values, item) => {
values[item.id] = item.name;
return values;
}, {});
在这种情况下,使用对象传播语法是否有赞成或反对的最佳做法?
在第一个代码中,您要为 .reduce
的每次迭代创建一个新对象。在某些引擎中,这可能比您的第二个代码效率稍低,后者仅创建一个对象。 (也就是说,效率很少很重要;在大多数情况下,代码清晰度更为重要)。
但是,对于这种情况,从数组创建对象时有一个更合适的方法,它避免了 reduce
:
const output = Object.fromEntries(
items.map(item => [item.id, item])
);
const items = [
{ id: 5, val: 5 },
{ id: 10, val: 10 },
{ id: 15, val: 15 },
];
const output = Object.fromEntries(
items.map(item => [item.id, item])
);
console.log(output);
也就是说,请记住 Object.fromEntries
是一项相对较新的功能,因此如果这是面向 public 的网站,请确保包含一个 polyfill。
...values
每次都会创建数组的浅表副本,如果数组很大,这可能会很昂贵。另一方面,在累加器上设置 属性 更有效。话虽如此,您可以确定您的数组肯定足够小,以至于您更喜欢简洁的展开语法。
出于性能原因,选项 2 显然更可取:
- 选项 1 在 O(n²) 时间内运行,因为扩展语法在每次迭代时复制 O(n) 个属性。选项 2 在 O(n) 时间内运行。
- 选项 1 创建 O(n²) 垃圾,因为它在每次迭代时创建大小为 O(n) 的垃圾对象。选项 2 不会产生垃圾。
就是说,在大多数情况下你应该只用一个普通的旧 for
循环来写这个:
let result = {};
for(let item of items) {
result[item.id] = item.name;
}
用for
循环也不错,而且代码比题中的两个选项更具可读性。选项 2 可能看起来更像是函数式编程风格,但如果您使用变异来实现您想要的结果,那么您并不是真正在进行函数式编程。
有关为什么选项 1 是反模式的更深入讨论,请参阅 this article。