【问题标题】:Index variable (_i) in for loops?for循环中的索引变量(_i)?
【发布时间】:2013-12-18 01:03:53
【问题描述】:

看看这个简单的代码:

eat = (x) -> console.log "nom", x

# dog only eats every second cat
feast = (cats) -> eat cat for cat in cats when _i % 2 == 0

feast ["tabby cat"
       "siamese cat"
       "norwegian forest cat"
       "feral cat"
       "american bobtail"
       "manx"]

$ coffee a.coffee 
nom tabby cat
nom norwegian forest cat
nom american bobtail

似乎_i 变量是当前索引。这是功能、错误还是 NaN?我还没有听到其他人谈论这个,所以我想知道是否有某些原因我不应该在我的代码中使用它?

【问题讨论】:

    标签: coffeescript undefined-behavior


    【解决方案1】:

    tldr-再次; CoffeeScript 的作者刚刚告诉我I'm right:不要使用_i

    14:29 <jashkenas> You shouldn't use internal variables. 
    ...
    14:42 <meagar> I was hoping something more deeply involved in the language would be able to put some authority behind that opinion 
    14:43 <meagar> ... I was basically hoping for an authoritative "don't do that" 
    14:44 <jashkenas> you just got it ;) 
    14:44 <jashkenas> for item, index in list -- there's your reference to the index. 
    

    tldr;这充其量是一个undocumented feature,其功能等效已记录功能存在。因此,它应该被使用。

    您关于“少打字”的论点非常可疑;比较:

    for x in [1, 2, 3] when _i % 2 == 0
      console.log "#{_i} -> #{x}"
    
    for x,i in [1, 2, 3] when i % 2 == 0
      console.log "#{i} -> #{x}"
    

    特性、错误还是 NaN?

    这些都不是;这是未定义的行为。您假设 _i 将是编译后的 JavaScript 中用于迭代的变量。

    你绝对不应该使用_i,或者假设_i 将被定义。这是一个实现细节,他们可以随时更改它。如果您的循环嵌套在另一个循环中,它也不会成为 _i;它将是_j_k 等。

    最重要的是,您可以在依赖底层实现的 JavaSript 变量的情况下做到这一点。如果要循环使用索引,只需使用for value,key in array

    array = ['a', 'b', 'c']
    
    console.log(index) for item, index in array # 0, 1, 2
    

    具体来说,在您的示例中:

    feast = (cats) -> eat cat for cat, index in cats when index % 2 == 0
    

    【讨论】:

      【解决方案2】:

      无需猜测或假设Coffeescript 做了什么。只看编译好的Javascript。在“试用 Coffeescript”标签中:

      feast = (cats) -> eat cat for cat in cats when _i % 2 == 0
      

      生产

      feast = function(cats) {
        var cat, _i, _len, _results;
        _results = [];
        for (_i = 0, _len = cats.length; _i < _len; _i++) {
          cat = cats[_i];
          if (_i % 2 === 0) {
            _results.push(eat(cat));
          }
        }
        return _results;
      };
      

      ...

      feast = (cats) -> eat cat for cat, index in cats when index % 2 == 0
      

      生成几乎相同的 JS,不同之处仅在于 index_i 一起使用或代替 _i

      feast = function(cats) {
        var cat, index, _i, _len, _results;
        _results = [];
        for (index = _i = 0, _len = cats.length; _i < _len; index = ++_i) {
          cat = cats[index];
          if (index % 2 === 0) {
            _results.push(eat(cat));
          }
        }
        return _results;
      };
      

      两者都有效,但index 让人类(包括你未来的自己)更清楚你的意图。正如其他人所说,避免使用未记录的实现特性是一种很好的编程实践——除非你真的需要它们。如果你正在做一些有趣的事情,请记录下来。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-04-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-13
        • 2019-07-05
        相关资源
        最近更新 更多