假设我有一个数组:

const ar = [1,2,3,4];


然后,我将reduce函数应用于该函数,在该函数中,我删除了像这样的元素:

ar.reduce((result, element, index, original)=>{
    original.pop();
}, []);


对于前两个元素,该函数将仅执行两次。这是可以理解的,因为我在之前的调用中删除了第3和第4个元素。

但是有趣的是,如果我执行该函数并删除当前元素:

ar.reduce((result, element, index, original)=>{
    original.splice(index, 1);
}, []);


该函数对于前两个元素仍然执行两次。为什么3rd4th元素不保留在数组中,为什么不执行呢?

此行为记录在任何地方吗?在规格上也许?

最佳答案

在第二个示例中,实际上是对第一个和第三个元素执行的,而不是对前两个执行:



const ar = [1, 2, 3, 4];

ar.reduce((result, element, index, original)=>{
    console.log(element, index);
    original.splice(index, 1);
}, []);

console.log(ar);





1 2 3 4
^


在这里,当reduce的element1并且index0时,它将调用splice,删除第一个元素,然后迭代到下一个索引:

2 3 4
  ^


在这里,reduce的element3,而index1。删除后,index等于ar.length并停止,让您

2 4


reduceRight()仍将访问所有元素的原因是因为您向后迭代,并且先前元素的位置不受在当前索引处拼接元素的影响:



const ar = [1, 2, 3, 4];

ar.reduceRight((result, element, index, original)=>{
    console.log(element, index);
    original.splice(index, 1);
}, []);

console.log(ar);





和演练:

element = 4, index = 3

1 2 3 4
      ^

element = 3, index = 2

1 2 3
    ^

element = 2, index = 1

1 2
  ^

element = 1, index = 0

1
^


要回答您的问题,是ECMAScript documents this behavior for Array#reduce() as part of the specification


  在第一次调用reduce之前设置callbackfn处理的元素的范围。 reduce调用开始后追加到数组的元素将不会被callbackfn访问。如果更改了数组的现有元素,则它们传递给callbackfn的值将是reduce访问它们时的值;在调用reduce之后且被访问之前删除的元素不会被访问。


与上述完全相同的段落也适用于reduceRight

以下是Array#reduce()的polyfill,遵循规范中的步骤:

Object.defineProperty(Array.prototype, 'reduce', {
  configurable: true,
  writable: true,
  value: Array.prototype.reduce || function reduce(callbackfn) {
    "use strict";
    // 1.
    if (this === undefined || this === null) {
      throw new TypeError("Array.prototype.reduce called on null or undefined");
    }
    let O = Object(this);
    // 2.
    let len = ToLength(O.length);
    // 3.
    if (typeof callbackfn != 'function') {
      throw new TypeError(`${String(callbackfn)} is not a function`);
    }
    // 4.
    if (len == 0 && arguments.length < 2) {
      throw new TypeError("Reduce of empty array with no initial value");
    }
    // 5.
    let k = 0;

    let accumulator;
    // 6.
    if (arguments.length >= 2) {
      // a.
      accumulator = arguments[1];
    // 7.
    } else {
      // a.
      let kPresent = false;
      // b.
      while (!kPresent && k < len) {
        // i.
        let Pk = String(k);
        // ii.
        kPresent = Pk in O;
        // iii.
        if (kPresent) accumulator = O[Pk]; // 1.
        // iv.
        k++;
      }
      // c.
      if (!kPresent) throw new TypeError("Reduce of empty array with no initial value");
    }
    // 8.
    while (k < len) {
      // a.
      let Pk = String(k);
      // b.
      let kPresent = Pk in O;
      // c.
      if (kPresent) {
        // i.
        let kValue = O[Pk];
        // ii.
        accumulator = callbackfn(accumulator, kValue, k, O);
      }
      // d.
      k++;
    }
    // 9.
    return accumulator;
  }
});

function ToInteger(argument) {
  let number = Number(argument);

  if (isNaN(number)) return 0;

  switch (number) {
  case 0:
  case Infinity:
  case -Infinity:
    return number;
  }

  return parseInt(number);
}

function ToLength(argument) {
  let len = ToInteger(argument);

  if (len <= 0) return 0;
  if (len == Infinity) return Number.MAX_SAFE_INTEGER || Math.pow(2, 53) - 1;

  return len;
}

关于javascript - 在将Array.reduce应用于数组时更改数组的后果是什么,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44682323/

10-13 07:11
查看更多