Coffeescript 在嵌套循环中关闭此引用列表

Coffescript closure _this reference lost within nested loops

这是我观察到的关于 CoffeeScript 的一些有趣的东西。

TLDR:{

我们知道粗箭头 (=>) 会生成一个闭包保存对 this 的引用,并且 @ 的每个引用都将替换为 [=16] 的原始值=].因此,以下 coffeescript 代码:

=>
  @sth

会产生以下结果:

(function(_this) {
  return (function() {
    return _this.sth;
  });
})(this);

注意 _this.sth.

}

但这是我发现的极端情况:

=>
  for a in sth
    for b in @sth
      sth

计算结果为:

(function(_this) {
  return (function() {
    var a, b, i, len, results;
    results = [];
    for (i = 0, len = sth.length; i < len; i++) {
      a = sth[i];
      results.push((function() {
        var j, len1, ref, results1;
        ref = this.sth;
        results1 = [];
        for (j = 0, len1 = ref.length; j < len1; j++) {
          b = ref[j];
          results1.push(sth);
        }
        return results1;
      }).call(_this));
    }
    return results;
  });
})(this);

这有点长,但问题是内循环遍历 this.sth 而不是 _this.sth

内循环的确切行数是:

ref = this.sth;
results1 = [];
for (j = 0, len1 = ref.length; j < len1; j++) {
  b = ref[j];

这是正常行为,还是错误?

仔细观察内循环:

results.push((function() {
  var j, len1, ref, results1;
  ref = this.sth;
  // Loop stuff goes here...
}).call(_this));

内部循环包含在一个函数中(作为循环理解代码的一部分),该函数使用 Function.prototype.call:

进行评估

The call() method calls a function with a given this value and arguments provided individually.

call 是用 _this 调用的(=> 中的 stashed/bound @)所以 this 在该函数中实际上是 _this 一切都很好。

如果您通过显式不返回任何内容来抑制理解代码:

=>
  for a in sth
    for b in @sth
      sth
  return

然后您会看到您最初期望的ref = _this.sth

(function(_this) {
  return (function() {
    var a, b, i, j, len, len1, ref;
    for (i = 0, len = sth.length; i < len; i++) {
      a = sth[i];
      ref = _this.sth; # <---------------------------
      for (j = 0, len1 = ref.length; j < len1; j++) {
        b = ref[j];
        sth;
      }
    }
  });
})(this);