views:

98

answers:

2

I have a code like this where I am trying to add an event handler to some button. I would like to use a global variable & store its current value in callback closure & not its reference.

var globalNum="dummy";
function A()
{
  $("#button").click(function()
  {
     $("#button").append(globalNum);
  });
}

globalNum="dummyAgain";

Now if click event is fired what would be added - "dummy" or "dummyAgain" ? I believe it would be "dummyAgain" coz for closure global variable's reference is stored. I want value to bind. I know I can create a local variable inside A which I can initialize with global variable & bind that but is there some other cooler way around too?

Thanks

+7  A: 

You are right, it would append dummyAgain. You can deal with this by using bind() and send some event data:

var globalNum="dummy";
(function A()
{
  $("#button").bind('click', {localNum: globalNum}, function(e)
  {
     $("#button").append(e.data.localNum);
  });
})();

globalNum="dummyAgain";

Note that I immediately execute the function A, so the click handler gets attached before the value of globalNum changes. As @Andrew points out in his comment, this is the same effect as not using the "wrapping" function A at all.


Same solution without bind:

(function()
 {
  var localNum = globalNum;
  $("#button").click(function()
  {
     $("#button").append(localNum);
  });
})();

Here the anonymous function is useful to capture the the current value globalNum in a local variable.


Update:

For the sake of completeness (I hope, @Andrew, you don't mind that I put it here). The "coolest" way is probably to use a parameter for the function and execute the function immediately with this parameter:

var globalNum="dummy";

(function(globalNum)
 {
  $("#button").click(function()
  {
     $("#button").append(globalNum);
  });
})(globalNum);

globalNum="dummyAgain";

The "trick" is that the name of the parameter and the name of the global variable are the same.

This is also very often used to refer to some object with a shorter identifier without polluting the global namespace, e.g. with jQuery:

(function($) {
    // jQuery == $
})(jQuery)
Felix Kling
+1 answer. It should be pointed out that @Felix_Kling is using using `bind()`, but also invoking `A()` before updating `globalNum`. This would be the equivalent, I think, of removing the `A()` function wrapper and executing the contents directly.
Andrew
Nikhil Garg
Then use @Felix Kling's answer with one minor change. Change `function A()` to `function A(globalParam)` and invoke it at the end with `})(globalParam);` Note that the `globalParam` inside the function will be different from the `globalParam` outside.
Andrew
@Andrew: Very good point, how could I forget about this :o)
Felix Kling
@Felix Kling: no problem. I personally think your first answer was clearer and probably easier to read, but this does nail the coolness factor!
Andrew
@Andrew: +1. Now this is cool enough for me! ;-)
Nikhil Garg
A: 

Maybe there is some cooler way, but declaring a local variable inside A is the most simple and direct way, hence the best.

Amnon