2

I'm trying to setup some key bindings in javascript for numbers 1 to 9 and click various links on the page which are labeled 'show1', 'show2', etc.

The problem is it creates the keybinding for the numbers ok but it always displays the last item, ie: 'show9'.

Here is an example where if you hit 1 or 2 on the keyboard the function will return 3, when it's supposed to return 1 & 2 respectively.

for i in [1..2]
    key i.toString(), (e) ->
        alert i

http://jsfiddle.net/DARxg/

Adam Rackis
  • 82,527
  • 56
  • 270
  • 393
map7
  • 5,096
  • 6
  • 65
  • 128

1 Answers1

3

The function you're creating has an enduring reference to the i variable, not a copy of it as of when the function was created, which is why you always see its final value (3).

Update: There's a more CoffeeScript-ish way at the end of the answer, although it's useful to read the whole thing so you understand the trade-offs.

Instead, use a builder function that creates functions that close over a different variable, one that doesn't change: Updated Fiddle

buildHandler = (value) ->
    (e) ->
        alert value
        return

for i in [1..2]
    key i.toString(), buildHandler i

There, our handler function closes over the argument we pass buildHandler, and so it doesn't change.

More: Closures are not complicated (but based on JavaScript, not CoffeeScript)


And for those who really like immediately-invoked function expressions (IIFEs) (I don't recommend IIFEs in loops, in theory it creates a new function every time just to throw it away, and it's hard to read):

for i in [1..2]
    key i.toString(), (
        (value) ->
            (e) ->
                alert value
                return
        )(i)

mu is too short points out in the comments that CoffeeScript has a keyword for doing exactly this: do It's near the end of this section of the documentation. Using it for this would look like this:

for i in [1..2]
    key i.toString(), do (i) -> (e) ->
        alert i
        return

Now, that gets translated to JavaScript that creates unnecessary functions and throws them away (like the IIFE above does), but for a number of use cases it probably doesn't matter. I'd still probably go for the clarity of my first option above, but it's good to have lots of tools in the belt.

Community
  • 1
  • 1
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875