0

If I compile this CoffeeScript:

    funcs = ((=> console.log i) for i in [0..2])                                                                                                                                                                                          

    funcs[0]()  // Prints 3
    funcs[1]()  // Prints 3
    funcs[2]()  // Prints 3

it produces this JavaScript:

    (function() {
      var funcs, i;

      funcs = (function() {
        var _i, _results,
          _this = this;
        _results = [];
        for (i = _i = 0; _i <= 3; i = ++_i) {
          _results.push(function() {
            return console.log(i);
          });
        }
        return _results;
      }).call(this);

      funcs[0]();

      funcs[1]();

      funcs[2]();

      funcs[3]();

    }).call(this);

I would think it would instead have:

          _results.push((function(i) {
             return function() {
              return console.log(i);
          }})(i));

Could someone explain why it's not doing that?

hippietrail
  • 15,848
  • 18
  • 99
  • 158
Nick
  • 5,228
  • 9
  • 40
  • 69
  • I think you have to do that explicitly: `((j) -> console.log j) for i in [0..2]`. – Blender Mar 03 '13 at 10:14
  • For more insight about the fat arrow have look here http://stackoverflow.com/questions/13184209/when-does-the-fat-arrow-bind-to-this-instance?rq=1 – robkuz Mar 04 '13 at 10:19

4 Answers4

1

Fat arrow binds this lexically, not every variable. Use do to capture variables using an IIFE.

funcs =
  for i in [0..2]
    do (i) ->
      -> console.log i
Ven
  • 19,015
  • 2
  • 41
  • 61
0

This is not how closures work. You get a closure when you return a function from another function scope:

var closure = (function(i) {
    return function() {
        console.log(i);
    };
})(i);

This can be achieved via this ugly CoffeeScript (no need for a fat arrow here):

funcs = ((do (j=i) -> -> console.log j) for i in [0..2])

I'd recommend to not write this as a single line though.

Niko
  • 26,516
  • 9
  • 93
  • 110
  • You must have typed this before my edit. My post had a mistake. Sorry about that. – Nick Mar 03 '13 at 10:24
  • @Nick Okay, the first bit is obsolete now. The CoffeeScript is however still a solution. – Niko Mar 03 '13 at 10:32
0

Okay, so after looking at the CoffeeScript documentation, I believe I've answered my own question. => only binds the function to the current value of this. I had mistakenly assumed it bound all variables to their current value.

...although it would be neat if it had a feature like that. Maybe ->>?

Nick
  • 5,228
  • 9
  • 40
  • 69
0

When you convert that coffee to javascript, you're getting a function that IS binding the scope. The problem is that:

funcs = (function() {
    var _i, _results,
      _this = this;
    _results = [];
    for (i = _i = 0; _i <= 3; i = ++_i) {
      _results.push(function() {
        return console.log(i);
      });
    }
    return _results;
  }).call(this);

in there, the variable i is bound, but by the time you call the function the value is 3, and remains in 3 every time you call the function.

Alex Siri
  • 2,856
  • 1
  • 19
  • 24
  • I realize it does that. But my question was about the fat-arrow's binding of the current scope on a per-function basis. It basically comes down to the fact that it only binds the current value of `this`. – Nick Mar 03 '13 at 10:37
  • Ok, so again, it IS binding the scope (meaning that the i variable you get is the same everywhere), but it is not binding the value (precisely because it is binding the scope). What you would need is a fresh variable (not bound) in each of the scopes. – Alex Siri Mar 03 '13 at 10:41
  • Right... I'm not challenging that. I'm not sure where the confusion lies. – Nick Mar 03 '13 at 10:42
  • Okay, I guess I was loose with my wording. Instead of "current scope" I should have said "the values of the current scope". – Nick Mar 03 '13 at 10:43