2012-07-12 72 views
0

我有一个包含对象的多维数组,我希望从数组中删除对象,如果它们包含特定的属性。bizzare未定义变量

CoffeeScript的

for dataColumn in allDataColumns 
    for brentSpiner, i in dataColumn 
     console.log i, brentSpiner.refreshRate 
     #dataColumn.remove i if brentSpiner.refreshRate is -1 

上述console.log作品时行波纹管被注释掉

for dataColumn in allDataColumns 
    for brentSpiner, i in dataColumn 
     console.log i, brentSpiner.refreshRate 
     dataColumn.remove i if brentSpiner.refreshRate is -1 

上述错误了,像这样的预期:brentSpiner is undefined console.log(i, brentSpiner.refreshRate);的萤火

怎么上地球可能在第二行的存在导致上述行中的变量becom未定义?

RENDERED JAVASCRIPT

失败

for (_i = 0, _len = allDataColumns.length; _i < _len; _i++) { 
    dataColumn = allDataColumns[_i]; 
    for (i = _j = 0, _len1 = dataColumn.length; _j < _len1; i = ++_j) { 
    brentSpiner = dataColumn[i]; 
    console.log(i, brentSpiner.refreshRate); 
    if (brentSpiner.refreshRate === -1) { 
     dataColumn.remove(i); 
    } 
    } 
} 

作品

for (_i = 0, _len = allDataColumns.length; _i < _len; _i++) { 
    dataColumn = allDataColumns[_i]; 
    for (i = _j = 0, _len1 = dataColumn.length; _j < _len1; i = ++_j) { 
    brentSpiner = dataColumn[i]; 
    console.log(i, brentSpiner.refreshRate); 
    } 
} 

(侧注:卸下摆臂已被添加到经由Resig的阵列原型)

UPDATE

这是我的一个逻辑错误。查看获得批准的答案以查看原因。贝娄是我落得这样做并运作良好:

for dataColumn in allDataColumns 
    i = 0 
    len = dataColumn.length 
    while i < len 
     if dataColumn[i].refreshRate is -1 
      dataColumn.remove i 
      len-- 
     i++ 

渲染

for (_i = 0, _len = allDataColumns.length; _i < _len; _i++) { 
    dataColumn = allDataColumns[_i]; 
    i = 0; 
    len = dataColumn.length; 
    while (i < len) { 
    if (dataColumn[i].refreshRate === -1) { 
     dataColumn.remove(i); 
     len--; 
    } 
    i++; 
    } 
} 
+0

从正在循环的数组中拉出元素是一种不稳定的操作。通过固定循环长度,coffeescript确保这将运行到最后,而不是跳过可能难以捕捉的元素。 – 2012-07-12 05:09:22

+0

您是否认为我的'while'循环版本也存在风险? – Fresheyeball 2012-07-12 20:07:57

+0

是的,因为当你删除一个元素时,你会跳过下一个元素。例如:列表是'[1,2,3]','i = 0'。如果我们决定删除'i',那么在while循环结束时我们有'[2,3]','i = 1'。下一个我们看到的是'3',所以我们跳过了'2'。我会在删除元素的'if'中减去'i',或者将增量放在'else'块中。我也建议不要冻结列表的长度 - 必须通过移除跟踪长度感觉很奇怪,并且从数组获得长度是恒定的时间。 – 2012-07-13 14:38:33

回答

0

的CoffeeScript在_len1“冻结”列表的长度。当你删除一个条目时,你会在内部循环中跑掉列表的末尾。

看起来像一个bug给我。 (除非有一些语言功能可以通知Coffeescript阵列长度可能会改变)

+0

http://tinyurl.com/d47ul7m trippy。这是有道理的,完全是我的错误。你有什么想法如何解决这个问题? – Fresheyeball 2012-07-12 00:57:47

+0

否;我不是Coffeescript的人:-)如果是的话,如果我在语言文档中找不到这种情况,我肯定会报告这是一个错误。 – Pointy 2012-07-12 00:58:49

+0

如何处理while循环? – Fresheyeball 2012-07-12 01:00:23

0

向/从正在循环的列表中添加/删除元素是一项危险的操作,而且非常危险一种语言难以自动处理。如果你需要这样做,你应该避免for..in循环,并坚持使用while循环。这是我会怎么写代码:

for dataColumn in allDataColumns 
    i = 0 
    while i < dataColumn.length 
     brentSpiner = dataColumn[i] 
     console.log i, brentSpiner.refreshRate 
     if brentSpiner.refreshRate is -1 
      dataColumn.remove i 
      i-- 
     i++ 

我也会改变你的代码的步骤,所以我们可以看到我是如何到达那里:

for dataColumn in allDataColumns 
    for brentSpiner, i in dataColumn 
     console.log i, brentSpiner.refreshRate 
     dataColumn.remove i if brentSpiner.refreshRate is -1 

首先,我们需要做的内环进入while循环。只要我们的计数器变量小于长度,我们就会循环,并在循环结束时递增计数器。为了保留语法,我们在循环中首先要设置循环变量brentSpiner

for dataColumn in allDataColumns 
    i = 0 
    while i < dataColumn.length 
     brentSpiner = dataColumn[i] 
     console.log i, brentSpiner.refreshRate 
     dataColumn.remove i if brentSpiner.refreshRate is -1 
     i++ 

现在,我们有一个问题,如果我们从列表中删除一个元素,因为下一个元素将被跳过。例如:列表是[1,2,3]i=0。如果我们决定删除i,那么在while循环结束时我们有[2,3],i=1。下一个我们将看到的项目是3,所以我们跳过了2。为了解决这个问题,我们每次移除一个位于当前计数器之前或之前的项目就会减少计数器。

for dataColumn in allDataColumns 
    i = 0 
    while i < dataColumn.length 
     brentSpiner = dataColumn[i] 
     console.log i, brentSpiner.refreshRate 
     if brentSpiner.refreshRate is -1 
      dataColumn.remove i 
      i-- 
     i++ 

如果我们还添加了元素,我们必须非常小心。我们可能不得不增加计数器,取决于元素的插入位置以及是否应该在循环中处理。