Closure/callback in for loop [duplicate]

2019-07-28 05:25发布

问题:

Possible Duplicate:
Event handlers inside a Javascript loop - need a closure?

I have been trying to get this to work for a while and decided to just ask.

I have the following:

function doSomething(var1, var2) {
    dojo.xhrGet({
        url:"somUrl",
        content: {value1:var1,value2:var2},
        preventCache: true,
        handleAs:"json",
        load: function(response){
            for(var i in response.myObject) {
                var listItem = new dojox.mobile.ListItem({
                    label: response.myObject[i].name,
                    rightText: response.myObject[i].value,
                    clickable: true, 
                    onClick: function() {
                        customFunction(response.myObject[i]);
                        this.transitionTo("someScreen");
                    }   
                });
                myList.addChild(listItem);
            }               
        },
        error:function(e){alert(e);}
    });
}
doSomething(myVal1, myVal2);

The line that says customFunction(response.myObject[i]); always returns the last object in the myObject arrray.

Can someone help me with the syntax so I can make this work correctly? I've been reading about js closures and callbacks but I just can't get it to work.

Thanks

回答1:

You need an additional wrapper function

onClick: (function(obj) {
    return function() {
        customFunction(obj);
        this.transitionTo("someScreen");
    };
})(response.myObject[i])

See this answer for an explanation:

JavaScript's scopes are function-level, not block-level, and creating a closure just means that the enclosing scope gets added to the lexical environment of the enclosed function.

After the loop terminates, the function-level variable i has the value 5 [note: or, in this case, the name of the last property in response.myObject], and that's what the inner function 'sees'.



回答2:

You need to ensure that i is contained in a closure in each iteration of the for-loop:

[...]
  load: function(response){
        for(var i in response.myObject) {
            var listItem = new dojox.mobile.ListItem({
                label: response.myObject[i].name,
                rightText: response.myObject[i].value,
                clickable: true, 
                onClick: (function(inner) {
                    return function (clickEvent) {
                      customFunction(response.myObject[inner]);
                      this.transitionTo("someScreen");
                    }
                }(i))   
            });
            myList.addChild(listItem);
        }               
    }
 [...]