简体   繁体   中英

Javascript For-Loop

Currently I'm working on a project using RaphealJS library and everything seems to be alright until I encountered a problem like this.

Instead of doing this multiple times :

   dolphinIcon[1].click(function() {              
           this.attr({  
             stroke: 'black', 'stroke-width': 2,  
             fill: 'green'  
           }); 
           alert(1);
   });

   dolphinIcon[2].click(function() {              
           this.attr({  
             stroke: 'black', 'stroke-width': 2,  
             fill: 'green'  
           }); 
           alert(2);
   });

  dolphinIcon[3].click(function() {              
           this.attr({  
             stroke: 'black', 'stroke-width': 2,  
             fill: 'green'  
           }); 
           alert(3);
   });

Why can't I just do this ?

for(var i=0; i<dolphinIcon.length; i++){
     dolphinIcon[i].click(function() {              
        this.attr({  
           stroke: 'black', 'stroke-width': 2,  
           fill: 'green'  
        });      
        alert(i);
     });
}

I just want each icon which is stored in the array to alert() the number of its index, but when I use for-loop, it always alert() the same number(size of the array) no matter which icon I clicked on. How should I fix this ?

This is a classic JavaScript problem. The variable i in each callback function is the same one, which will be dolphinIcon.length once the loop is done.

You need to use a closure to "capture" the i variable.

var clickFunc = function(i){
    return function(){
        this.attr({  
           stroke: 'black', 'stroke-width': 2,  
           fill: 'green'  
        });      
        alert(i);
    }
};
for(var i=0; i<dolphinIcon.length; i++){
     dolphinIcon[i].click(clickFunc(i));
}

clickFunc will return a function that "closes" on the value of i .

You can also pass extra data to the click handler, to be used once it's called.

for(var i=0; i<dolphinIcon.length; i++){
     dolphinIcon[i].click({i: i}, function(e) {              
        this.attr({  
           stroke: 'black', 'stroke-width': 2,  
           fill: 'green'  
        });      
        alert(e.data.i);
     });
}

This is because of the way javascript closure works -- basically, your callback/event handling functions are binding to the loop variable i rather than to specific values of i in successive iterations of the loop.

Here's the simple workaround: simply wrap the interior of your loop with an anonymous function, and pass the loop variable to that function. This will cause the closure to attach to that specific value.

For example:

for(var i=0; i<dolphinIcon.length; i++)
{
    (   function(i) 
        {
            dolphinIcon[i].click(function() 
            {              
                this.attr({ stroke: 'black', 'stroke-width': 2, fill: 'green'});      
                alert(i);
            } );
        } )( i );
}

Try this:

for(var i=0; i<dolphinIcon.length; i++){ 
     dolphinIcon[i].bind('click', {index: i}, function(e) {             
        $(this).attr({   
           stroke: 'black', 'stroke-width': 2,   
           fill: 'green'   
        });       
        alert(e.data.index); 
     }); 
}

I'd like to suggest the underscore.js library. It contains many utility methods of dealing with arrays and onbject (in your case each and bind) http://underscorejs.org/#each

In your example this code would be reduced to:

_.each(dolphicons, function(dolphicon, index){  
    var func = function() {              
        this.attr({  
           stroke: 'black', 'stroke-width': 2,  
           fill: 'green'  
        });      
        console.log(index);
    }
    func = _.bind(func, dolphicon);

    dolphicon.click(func);
});

"this" will refer to the dolphicon because the bind. example alsoo at: http://jsfiddle.net/SyJdv/

You could alsoo scope the function outside the each loop

var func = function() {              
   this.obj.attr({  
      stroke: 'black', 'stroke-width': 2,  
      fill: 'green'  
    });      
    console.log(this.index);
}

_.each(dolphicons, function(dolphicon, index){  
   var clickfunc = _.bind(func, {obj: dolphicon, index: index});    
   dolphicon.click(clickfunc);
});

http://jsfiddle.net/PW9WX/1/

Here I provide you a link of a code that I prepare to explain you with examples and details about: JavaScript for loop in three different ways, click the link read the code, test yourself and give a like.

https://code.sololearn.com/WHc3WmA7TrMP

Bellow is the code:

<!DOCTYPE html>
<html>
   <body>

      <script type="text/javascript">
         /*
        The For Loop. Bellow are three examples using the same code in different ways, 
        returning the same results. Before let's explain which are the components fo the for loop.

        for loop have 3 components:
        1.initialization 
        2.condition
        3.Iteration 

      syntax: for (Initialization;condition;iteration)

        e.g.: for (i=1; i<=5; i++)

        In JavaScript <br> this tag is used as a line break.
        */

        //The example below creates a for loop that prints numbers 1 through 5.
        document.write("The example below creates a for loop that prints numbers 1 through 5. <br/>");
        for (i=1; i<=5; i++) {
           document.write(i + "<br />"); // <br /> is use to line break
        }

        //Statement 1 is optional, and can be omitted, if your values are set before the loop starts.
        document.write("<br/> Statement 1 is optional, and can be omitted, if your values are set before the loop starts. <br/>");
        var i = 1;
        for (; i<=5; i++) {
           document.write(i + "<br />");
        }

        //Also, you can initiate more than one value in statement 1, using commas to separate them.
        document.write("<br/> Also, you can initiate more than one value in statement 1, using commas to separate them. <br/>");
        for (i=1, text=""; i<=5; i++) {
            text = i;
            document.write(text + "<br />");
        }

        /* 
        If you notice in the for loop in JavaScript is not mandatory to declare explicitly a variable.
        e.g.: for (i=1; i<=5; i++) {}

        this is equivalent to say:
        for (var i=1; i<=5; i++) {}

        */

        // the following code will generate an infinite loop if you do not include break;
        var i = 0;
        for (; ; ) {
            document.write(i);
            i++;
            // if you comment or delete the break, this for loop will never end
            break;
        }

      </script>

      <p>Please like this code, I hope it helps you to learn more about For Loop ...</p>
   </body>
</html>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM