1

Throughout my script I am calling the function dynamo.toolbox.add_temp_button. An example of this is here:

if(page < total_pages){
    dynamo.toolbox.add_temp_button("Next Page",function(){
        dynamo.shop.enter.access(page+1,data.shop_zbid);
    });
}

As you can see in this call, two parameters are passed, page+1 and data.shop_zbid. Now these values aren't constants and change rapidly due to the overall function of the script.

Now here's the function itself:

add_temp_button : function(text,callback){
    var id = text.toLowerCase().replace(/[^A-Za-z_]/g,"_");
    callback = callback !== undefined && callback !== null ? callback : function(){};
    var but = '<button value="'+text+'" id="jqi_state0_button'+id+'" name="jqi_state0_button'+id+'" class="dynamo_temp_button">'+text+'</button>';
    $("#jqi_state0_buttonClose").before(but);
    $("#jqi_state0_button"+id).bind('click',callback);
},

Do note that this has been stripped out of my script, but it is called by dynamo.toolbox.add_temp_button.

Now, I need to know if this forms a closure, i.e will the value of the parameters I pass into the add_temp_button function be set in stone?

My biggest worry here is the second parameter, callback. This is a function which is passed as the callback function to $.bind. When the bound event is triggered, will it use the current value of page and callback, or that which was passed initially?

Thank-you!

Keir Simmons
  • 1,634
  • 7
  • 21
  • 37
  • 1
    Yes it's a closure, and yes it will use the *current* values when the callback is run. Look at this example: http://jsfiddle.net/uGVHd/ – asawyer Aug 27 '12 at 18:25
  • You may find this useful for an explanation: http://stackoverflow.com/questions/3572480/please-explain-the-use-of-javascript-closures-in-loops/3572616#3572616 – slebetman Aug 27 '12 at 18:31
  • Unlike what is being suggested, the callback function is ***not*** a closure. If it was being created inside of the outer-function (ie: inside of the `if` scope, rather than inside of the call to `build_temp_button`), then yes, it would have closure access (`if (...) { myCB=fn(a,b){...}; ...(page+1,myCB); }`). Right now, the callback does not. But you can wrap it in an anonymous function, which passes your intended values ***TO*** the created and returned callback function (the anonymous function becomes the new closure-scope). This sounds weird... It is. See Martin's correct answer, below. – Norguard Aug 27 '12 at 18:52

1 Answers1

1

change

if(page < total_pages){
    dynamo.toolbox.add_temp_button("Next Page",function(){
        dynamo.shop.enter.access(page+1,data.shop_zbid);
    });
}

to

if(page < total_pages){
    dynamo.toolbox.add_temp_button("Next Page",(function(a,b){
        return function() { dynamo.shop.enter.access(a,b); }
    })(page+1,data.shop_zbid));
}

and you will get what you are after - you need to make the values of page+1 and data.shop_zbid local to the callback for the desired effect, otherwise they can be modified outside the callbacks scope before the callback is called

Martin Jespersen
  • 25,743
  • 8
  • 56
  • 68
  • I think you mean to make the callback `(function (a,b){ return function () { dynamo.shop.enter.access(a,b); }; }(page+1, data.shop_zbid));` As it is, even if the browser fires your anonymous function, due to the comma (normally, that would be a syntax-error to have an immediately-invoked, nameless function that wasn't wrapped in something which caused it to be evaluated)... The next problem is that you wouldn't be binding the function `dynamo.... access(a,b)`... you'd be invoking it instantly and assigning the return value of it (probably an error). – Norguard Aug 27 '12 at 18:33
  • @Norguard: No, you are wrong on both accounts. it is how i emant it, and it is not an error in any current browser. calling a function like that is perfectly valid, but if you feel like it you can wrap it like so: (function(){})() but there is no real difference in this scenario – Martin Jespersen Aug 27 '12 at 18:36
  • Show me how. When your function evaluates it sets the value of `dynamo...access(a,b);`. That's what's in your function. So you're running that function as soon as you call the `add_temp_button()` function, rather than assigning an anonymous function, which, when run, applies the newly-scoped `a, b` into the function. – Norguard Aug 27 '12 at 18:40
  • Right. That is an immediate invocation of "hey". It's not binding an anonymous function to a button (or whatever the internal requirement of `add_temp_button` is). `sayHey = function (a) { alert(a); }`. `button.onclick = function (words) { sayHey(words); }("Hey");` Button.onclick is `undefined`, versus button.onclick = function (words) { return function () { sayHey(words); }; }("Hey"); – Norguard Aug 27 '12 at 18:42
  • youa re right, i was missing your point, sorry, sitting here with a 3 week old baby and only using half a brain :) – Martin Jespersen Aug 27 '12 at 18:46
  • No worries. Callbacks in JS are an inconvenience at the best of times. – Norguard Aug 27 '12 at 18:47
  • Thank-you for your answer. Can I just ask how this works? When I call the dynamo...temp_button, does it instantly create a function with my intended values and then passes it as the callback? Could you explain how this is different to my original function? I'm having a huge problem understanding closures properly! – Keir Simmons Aug 27 '12 at 18:59
  • Try to read the following articles, that should clear up any confusion around scoping and closures: http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting and http://lostechies.com/derekgreer/2012/02/17/javascript-closures-explained/ – Martin Jespersen Aug 31 '12 at 17:03