Note that there are some explanatory texts on larger screens.

plurals
  1. POIssue with Coffeescript comprehensions and closures
    primarykey
    data
    text
    <p>I ran into a problem when converting some JavaScript to CoffeeScript. The basic issue is I went from using $.each to CoffeeScript comprehensions and I now have a problem where the last value of the comprehension is being captured in closures. Lets start with the original JavaScript:</p> <pre><code>function bindKeyboardControls(websocket) { var moveKeyMap = { Down: ['down', 's'], Up: ['up', 'w'], Left: ['left', 'a'], Right: ['right', 'd'] }; $.each(moveKeyMap, function (direction, keys) { $.each(keys, function (_, key) { $(document).bind('keydown', key, function () { move(websocket, direction); }); }); }); }; </code></pre> <p>Here is my first attempt with CoffeeScript:</p> <pre><code> bindKeyboardControls = (websocket) -&gt; moveKeyMap = Down: ['down', 's'] Up: ['up', 'w'] Left: ['left', 'a'] Right: ['right', 'd'] for direction, keys of moveKeyMap for key in keys $(document).bind('keydown', key, -&gt; move(websocket, direction)) null </code></pre> <p>Why doesn't this work? Well here's the generated JavaScript:</p> <pre><code>bindKeyboardControls = function(websocket) { var direction, key, keys, moveKeyMap, _i, _len; moveKeyMap = { Down: ['down', 's'], Up: ['up', 'w'], Left: ['left', 'a'], Right: ['right', 'd'] }; for (direction in moveKeyMap) { keys = moveKeyMap[direction]; for (_i = 0, _len = keys.length; _i &lt; _len; _i++) { key = keys[_i]; $(document).bind('keydown', key, function() { return move(websocket, direction); }); } } return null; }; </code></pre> <p>Do you see how the 'direction' variable is declared at the top of the function? The function that is being passed in to document.bind is creating a closure on that variable, so by the time the function runs, direction will always be equal to the last value ('Right').</p> <p>Here is a fixed version that is somewhat ugly:</p> <pre><code> bindKeyboardControls = (websocket) -&gt; moveKeyMap = Down: ['down', 's'] Up: ['up', 'w'] Left: ['left', 'a'] Right: ['right', 'd'] for direction, keys of moveKeyMap for key in keys ((d) -&gt; $(document).bind('keydown', key, -&gt; move(websocket, d)))(direction) null </code></pre> <p>I could also just go back to using $.each. So I do have some solutions, but is there a better one?</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload