How to get current loop iteration from anonymous f

2019-07-25 14:33发布

问题:

Possible Duplicate:
Javascript closure inside loops - simple practical example

I have a for loop with an anonymous function inside, and in the function I want to access the current loop iteration. But for some reason instead of the loop iteration, I'm getting 4. The only other place 4 is a value is myArray.length. If I pass i as an argument, I get [object Object] out. What am I doing wrong? My code:

var width = function(){
   for(var i = 0, len = myArray.length; i < len; ++i){
      alert(i) //this outputs the current iteration
      myArray[i].load(function(){
         alert(i) //this outputs 4 (or [object Object])
      });
   };
};

Thanks.

回答1:

Your anonymous function passed to .load is being executed way after your loop has finished.

You have to create a local scope, and copy the i variable:

var width = function(){
    for(var i = 0, len = myArray.length; i < len; ++i){
        (function(i){
            myArray[i].load(function(){
                alert(i) //this outputs 4 (or [object Object])
            });
        })(i);
    };
};


回答2:

ECMAScript 5 includes bind()[docs], which is used to get a function with the this value as well as argument values bound to it.

function loader( i ){
    alert( i );
}

var width = function(){
   for(var i = 0, len = myArray.length; i < len; ++i){
      alert( i );
      myArray[i].load( loader.bind( null, i )  );
   }
};

Here I bound null as the this value in the function returned, but you can set it to something else. Then I bound the current value of i as the first argument.


To get support for older browsers (if needed), include the shim from MDN:

if (!Function.prototype.bind) {
    Function.prototype.bind = function (oThis) {
        if (typeof this !== "function") // closest thing possible to the ECMAScript 5 internal IsCallable function
        throw new TypeError("Function.prototype.bind - what is trying to be fBound is not callable");
        var aArgs = Array.prototype.slice.call(arguments, 1),
            fToBind = this,
            fNOP = function () {},
            fBound = function () {
                return fToBind.apply(this instanceof fNOP ? this : oThis || window, aArgs.concat(Array.prototype.slice.call(arguments)));
            };
        fNOP.prototype = this.prototype;
        fBound.prototype = new fNOP();
        return fBound;
    };
}

This is a mostly compatible shim that will work for most cases.