为什么递减函数调用中的参数在 javascript 中不起作用?

Why doesn't decrementing an argument in a function invocation work in javascript?

在一个 Java 脚本项目中,我在一个列表中循环,有时使用 splice() 删除当前元素。现在,显然需要递减迭代变量以不遗漏任何元素。看起来像这样:

for (var i = 0; i < list.length; ++i) { 
  if (...){
    list.splice(i,1); 
    --i
  }
}

现在,来自 Java,我想我可以通过在将变量作为参数传递后递减变量来保存一行,如下所示:

for (var i = 0; i < list.length; ++i) { 
  if (...)
    list.splice(i--,1)
}

答案表明它应该有效。 使用 paper.js 时出现问题 - 我为此打开了一个 issue on github。似乎 paper.js 在将其值传递给 splice() 之前递减 i,导致实际调用 splice(-1,1)。索引为 -1 时,splice() 将删除列表的最后一项。在下一次循环迭代中,i 将被加回到 0,对 list[0] 的检查仍将评估为 true,因为元素仍然存在,相同的调用 splice(-1,1) 将发生删除最后一个元素,依此类推。

查看损坏的行为here:点击按键会创建缩小的圆圈,当低于区域 1 时,会从 canvas 和包含它们的数组中移除。在第 17 行调用 splice() 时会出现此问题。

很好奇,这个问题 - 感谢您的帮助!

两种方式之间没有区别(在 splice 调用或下一行递减 i 参数)因为您使用的是 post-decrement 运算符。

post-decrement 我的意思是当 -- 运算符用作后缀(即 i--)时:在这种情况下,它 returns 递减前的当前值。而且,这就是为什么您的问题中使用的两个备选方案是等价的。

关于i变量的类型,可以用typeof运算符查看。在这种情况下是一个 number 对象,它属于标量基元组 (NumberStringBooleanundefinednullSymbol)。所有原始值都是按值分配的。只有 javascript 中的复合值通过引用分配(ObjectArray)。

您可以阅读更多关于 javascript arithmetic operators

检查两种情况的输出:

function test(list, condition) {
    const list1 = [...list];
    for (var i = 0; i < list1.length; i++) {
      if (condition(list1[i], i)) {
        list1.splice(i--, 1);
      }
    }
    console.log('output using decrement on splice arg', list1);
    
    const list2 = [...list];
    for (var i = 0; i < list2.length; i++) {
      if (condition(list2[i], i)) {
        list2.splice(i, 1);
        i--;
      }
    }
    console.log('output decrementing after splice', list2);
}

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

test(list, (elem, index) => elem % 2 === 0);
// -> [1, 3]
// -> [1, 3]

test(list, (elem, index) => index % 2 !== 0);
// -> [1]
// -> [1]


我在您的代码中看到的问题是循环内的 if 条件。如果您的测试以某种方式包含索引,可能会导致您删除额外的元素(一开始就不是故意的)。

第二个示例,使用基于元素索引的条件,并举例说明了当我们尝试删除奇数位置上的所有元素时可能出现的情况。发生这种情况是因为在第二次迭代 (i=1) 中,测试的计算结果为 true,并且 i-- 的递减步回到零 (i=0)。然后 for 增量起作用,我们再次测试之前的场景:i=1.

无论您是在 splice 调用中还是之后递减内联迭代变量,先前的行为都保持不变。