【问题标题】:bizzare undefined variable奇怪的未定义变量
【发布时间】:2012-07-11 17:18:14
【问题描述】:

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

咖啡脚本

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); in firebug

第二行的存在究竟如何导致上一行中的变量未定义?

渲染的 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);
  }
}

(旁注:.remove 已通过 Resig 添加到 Array 原型中)

更新

这是我的一个逻辑错误。查看批准的答案以了解原因。贝娄是我最终做的并且效果很好:

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++;
  }
}

【问题讨论】:

  • 从被循环的数组中拉出元素是一个不稳定的操作。通过固定循环长度,coffeescript 确保循环结束,而不是跳过可能更难捕捉的元素。
  • 您认为我的while 循环版本也包含风险吗?
  • 是的,因为当你删除一个元素时,你会跳过下一个元素。示例:列表为[1,2,3]i=0。如果我们决定删除i,那么在while 循环结束时我们有[2,3]i=1。我们要查看的下一项是3,因此我们跳过了2。我会在删除元素的if 内减少i,或者将增量放在else 块中。我还建议不要冻结列表的长度 - 必须通过删除来跟踪长度感觉很奇怪,并且从数组中获取长度无论如何都是恒定的时间。
  • @AaronDufour 你说得有道理。我在 if 语句中添加了减量,因此在数组长度丢失一个的情况下,索引在下一次迭代中保持不变。你愿意为你认为应该做的方式写一个答案吗?
  • 完成。它可能与您的代码几乎相同,在循环的开头多了一行,让我们更容易看到它与for..in 版本的关系。

标签: javascript jquery coffeescript


【解决方案1】:

在被循环的列表中添加/删除元素是一个危险的操作,语言很难自动处理这个问题。如果你需要做这样的事情,你应该避免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++

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

【讨论】:

    【解决方案2】:

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

    对我来说似乎是一个错误。 (除非有某种语言特性可以通知 Coffeescript 数组长度可能会改变。)

    【讨论】:

    • tinyurl.com/d47ul7m 迷幻。这是有道理的,完全是我的错误。您对如何解决这个问题有任何想法吗?
    • 否;我不是 Coffeescript 人 :-) 如果我是的话,如果我在语言文档中没有提到这种情况,我肯定会将此报告为错误。
    • @Fresheyeball 向后循环数组。我不确定 CoffeeScript 中的语法。
    • @RussFerri 为什么会有帮助?
    • @Fresheyeball 你看到我的回答了吗?顺便说一句:如果你向后迭代,数组的长度会缩小并不重要,因为你从后面删除并走到前面。
    猜你喜欢
    • 2021-11-19
    • 1970-01-01
    • 2018-03-05
    • 1970-01-01
    • 2012-05-16
    • 1970-01-01
    • 2018-10-26
    • 2014-03-09
    • 2012-04-22
    相关资源
    最近更新 更多