如何使用带累加器的数组映射?
让我们有一个数字列表,并找到当前总和的列表。 例如:
const nums = [1, 1, 1, -1, -1];
const sums = [1, 2, 3, 2, 1];
我尝试使用map
中的累加器来thisArg
,因为根据:MDN Array.prototype.map()
thisArg
- 执行回调时用作this
的值。
我提供acc
设置为0
thisArg
的对象:
const actual = nums.map(val => this.acc += val, {acc: 0});
require('assert').deepEqual(actual, sums);
崩溃时出错:
AssertionError: [ 1, 2, 3, 2, 1 ] deepEqual [ NaN, NaN, NaN, NaN, NaN ]
测试通过外部累加器:
let acc = 0;
const actual = nums.map(val => acc += val);
答案 0 :(得分:14)
使用arrow functions时,您在函数中松开了this
,该函数已经从外层空间设置。
您可以使用function statement 和 thisArg
。
const nums = [1, 1, 1, -1, -1];
const actual = nums.map(function (val) { return this.acc += val; }, { acc: 0 });
console.log(actual);

为了保持箭头功能,你可以在累加器上使用closure,
(acc => val => acc += val)(0) // complete closure with callback
分为两步,首先直接使用acc
(acc => )(0) // function for generating a closure over acc
并返回内部函数作为Array#map
val => acc += val // final callback
有一个超过acc
的闭包,这意味着acc
的范围在自己的函数内部和返回的回调内部。
const nums = [1, 1, 1, -1, -1];
const actual = nums.map((acc => val => acc += val)(0));
console.log(actual);

答案 1 :(得分:1)
您可以改用Array.prototype.reduce()
。
这不需要您为箭头函数创建额外的闭包,并将累加器作为常规参数提供。
const nums = [1, 1, 1, -1, -1]
const actual = nums.reduce(
(acc, val) => (acc.push((acc[acc.length-1] || 0) + val), acc), []
)
console.log(actual) // [1, 2, 3, 2, 1]
<强> 编辑: 强>
如果您担心表现,可以使用jsPerf与您和@ Nina的选项进行比较:
.map()
具有标准功能 - 在Firefox中慢27%,在Chrome中比使用工厂功能.map()
快5%.reduce()
在Firefox中慢了94%,在Chrome中慢了52%,而不是上面两个中最快的。.map()
快75%!