在JavaScript中使用累加器的数组映射

时间:2017-12-25 11:23:51

标签: javascript dictionary

如何使用带累加器的数组映射?

让我们有一个数字列表,并找到当前总和的列表。 例如:

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);

2 个答案:

答案 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%