2013-02-16 122 views
-1

我在嵌套for循环中使用splice,我遇到了一个我无法理解的行为。javascript拼接跳过元素 - 为什么这个行为

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后拼接() ...那么它是如何拼接的?

+0

在JavaScript中使用'for ... in'循环与数组不是一个好主意(通常)。使用索引变量。 – Pointy 2013-02-16 14:28:25

+0

我已更新[我的答案](http://stackoverflow.com/a/14911384/157247)以回应您的修改。 – 2013-02-16 18:09:18

回答

4

为什么是指价值指数3 2,而它应该是指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"并且索引0处的条目为0,因此您的日志语句显示"0==0"splice调用,a没有改变,所以它仍然是这样的:

    [0, 1, 2, 3, 4] 
    
  3. 在你的内循环的下传,c"1",并且在指数1的条目是1,所以你的日志语句显示"1==1"。然后splice叫,改变a所以它看起来是这样的:

    [0, 2, 3, 4] 
    
  4. 在你的内循环的下传,c"2",并在指数2项是3(不2,因为a已更改),所以您的日志语句显示"2==3"

后来,当你的外环再次运行,再次c"1"在一个点,所以另一个条目被删除,你会看到同样的效果。

你应该做的是实际观察代码的运行情况,单步执行调试程序,并观察如何实时更改a。所有现代浏览器都内置了功能强大的调试器,您不必乱抛垃圾代码console.log报表,您实际上可以发现。


这不是你的问题的原因,但要注意for-in不是遍历数组索引,它是枚举对象的属性名称(这就是为什么你c==="1"比较有效,属性名称始终字符串)。更多:Myths and realities of for..in

2

后删除元素1,然后 “一” 的样子:

[0, 2, 3, 4] 

元素1是2循环的下一次迭代,然后 “c” 是2,并a[2]确实是3.

0

您应该not use for…in-enumerations to loop arrays

这就是说,你的问题是,.splice method修改你的数组,删除一个项目,并调整后的指标。然而,你不调整你的迭代变量,所以它会跳过索引 - 已经访问了旧索引“1”,接下来将是“2”而不是新的“1”。

要解决这个问题,您可以向后循环或通过数字或删除的项目减少迭代计数器。但是,当重新访问索引时,您的条件将始终得到满足,并且您将连续删除阵列中的所有第二个元素,直到没有第二个元素为止 - 不确定这是否是您的目标。