0

splice在嵌套的 for 循环中使用,遇到了我无法理解的行为。

var a = [0, 1, 2, 3, 4];

for (b in a) {
    console.log(a);
    for (c in a) {
        console.log(c + '==' + a[c]);
        if (c === "1")
            a.splice(c, 1);
      }
 }

console.log(a);

它的输出很奇怪

    [0, 1, 2, 3, 4]
    "0==0"
    "1==1"
    "2==3"  // why is index 2 referring to value 3 , whereas it should refer to 2
    "3==4"
    [0, 2, 3, 4]
    "0==0"
    "1==2"
    "2==4"  //  index 2 referring to value 4 , whereas it should refer to 3
    [0, 3, 4]
    "0==0"
    "1==3"
    [0, 4]

我正在拼接索引 1,它正在跳过下一个元素。

为什么这种行为...

在这里结帐:http: //jsbin.com/isahoj/3/edit

编辑:
好的,我知道它在拼接之后会移动索引,但是我在执行 console.log() 之后调用 splice ... 那么它是如何更早拼接的呢?

4

3 回答 3

5

为什么索引 2 引用值 3 ,而它应该引用 2

因为在上一次迭代中,您通过以下方式删除了一个条目splice

if (c==="1")
    a.splice(c, 1);

...所以一切都转移了(就是splice这样)。然后下一个循环继续c"2",索引 2 处的条目(现在)是3


回复您的评论:

好的,我知道它在拼接后会移动索引,但是我在做console.log()之后调用了拼接......那么它是如何更早拼接的呢?

好吧,让我们退后一步:

  1. 在内部循环开始之前,a看起来像这样:

    [0, 1, 2, 3, 4]
    
  2. 在你的内部循环的第一遍,c"0"并且索引处的条目00,所以你的日志语句显示"0==0"没有splice被调用,也没有改变,所以它仍然看起来像这样:a

    [0, 1, 2, 3, 4]
    
  3. 在你的内部循环的下一次传递中,c"1",并且索引处的条目11,所以你的日志语句显示"1==1"。然后splice 调用,改变a它看起来像这样:

    [0, 2, 3, 4]
    
  4. 在你的内部循环的下一次传递中,c"2",并且索引处的条目23(不是2,因为a已经改变),所以你的日志语句显示"2==3"

稍后,当您的外部循环再次运行时,c"1"在某一点,因此另一个条目被删除,您会看到相同的效果。

a您应该做的是实际观看代码实时运行,使用调试器单步执行,并实时观察变化情况。所有现代浏览器都内置了功能强大的调试器,您不必在代码中乱扔console.log语句,您可以实际观察发生的情况。


这不是您的问题的原因,但请注意,这for-in不是用于循环数组索引,而是用于枚举对象的属性名称(这就是您的c==="1"比较有效的原因,属性名称始终是字符串)。更多:神话和现实for..in

于 2013-02-16T14:32:18.007 回答
2

删除元素 1 后,“a”看起来像:

[0, 2, 3, 4]

新元素1是2。循环下一次迭代,那么“c”是2,a[2]确实是3。

于 2013-02-16T14:32:40.153 回答
0

您不应该使用for…in-enumerations 来循环数组

也就是说,您的问题是该.splice方法修改了您的数组,删除了一个项目并在它之后调整了 indizes。然而,你没有调整你的迭代变量,所以它会跳过索引——旧索引“1”已经被访问过,下一个将是“2”而不是新的“1”。

要解决此问题,您可以向后循环或将迭代计数器减少数量或删除的项目。但是,在重新访问索引时,您的条件将始终得到满足,并且您将依次从数组中删除所有第二个元素,直到没有第二个元素 - 不确定这是否是您的目标。

于 2013-02-16T14:35:32.417 回答