Late binding onclick event

2019-09-04 19:56发布

问题:

Following part of my javscript(using jquery).

list = ['a', 'b', 'c'];
for(var i = 0 ; i< list.length ; i++) {
   $("<a>click here</a>").
      click(function(){
          foo(list[i]);
      }).
      appendTo('#sometag');
}
function foo(val) {
    console.log(val);
}

always prints c, no matter which tag you click on. How do I print proper value ???
It seems that it is using the last value of i=3 and thus evaluating o c always

回答1:

You'll need a closure new scope as the iteration finishes before the event handler is triggered, so when the click happens, the loop has finished and i is the last value it's set to, a new scope keeps the value of i local to that scope

list = ['a', 'b', 'c'];

for(var i=0; i<list.length; i++) {

   (function(j) {

       $("<a>click here</a>").click(function(){
          foo(list[j]);
       }).appendTo('#sometag');

   }(i));

}

function foo(val) {
    console.log(val);
}

Another option is to add more jQuery

list = ['a', 'b', 'c'];

$.each(list, function(index, item) {
    $("<a />", {text : 'click here',
                on   : {
                    click : function() {
                        foo(item);
                    }
                }
    }).appendTo('#sometag');
});

function foo(val) {
    console.log(val);
}


回答2:

Create a closure to retain the value of i for the particular iteration when the function is executed, without a closure i remains in scope causing all of the created functions to eventually have the value at the last iteration:

var list = ['a', 'b', 'c'];
for(var i = 0 ; i< list.length ; i++) {
   var func = createFoo(list[i]);
   $("<a>click here</a>").
      click(func).
      appendTo('#sometag');
}
function createFoo(value){
    return function(){
        foo(value);
    };
}
function foo(val) {
    console.log(val);
}

JS Fiddle: http://jsfiddle.net/5dUgw/

Also note you need to change int to var since this is JS.