<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Closure demonstration</title> </head> <body> <p>1</p> <p>2</p> <p>3</p> <p>4</p> <p>5</p> <script type="text/javascript"> window.onload=function() { var ps = document.getElementsByTagName("p"); for( var i=0; i<ps.length; i++ ) { ps[i].onclick = function() { alert(i); } } } </script> </body> </html>
Reason: js event processor will not run when the thread is idle, resulting in the output of the last value of i, that is: 5
2. Solution: use closures to protect the value of variable i.
sava1: add a layer of closure, and i is passed to the inner layer function in the form of function parameter
for( var i=0; i<ps.length; i++ ) { (function(arg){ ps[i].onclick = function() { alert(arg); }; })(i);//Call time parameters }
//save2: add a layer of closure, and i is passed to the memory function in the form of local variable
for( var i=0; i<ps.length; i++ ) { (function () { var temp = i;//Local variable on call ps[i].onclick = function() { alert(temp); } })(); }
//save3: add a layer of closure and return a function as the response event (note the subtle difference with 3)
for( var i=0; i<ps.length; i++ ) { ps[i].onclick = function(arg) { return function() {//Returns a function alert(arg); } }(i); }
//save4: save variable i to each paragraph object (p)
for( var i=0; i<ps.length; i++ ) { ps[i].i = i; ps[i].onclick = function() { alert(this.i); } }
//save5: save variable i in anonymous function itself
for( var i=0; i<ps.length; i++ ) { (ps[i].onclick = function() { alert(arguments.callee.i); }).i = i; } }
//save6: implemented with Function. In fact, each Function instance will generate a closure
for( var i=0; i<ps.length; i++ ) { ps[i].onclick = new Function("alert(" + i + ");");//new generates a function instance at a time }
//save7: implemented with Function, note the difference with 6
for( var i=0; i<ps.length; i++ ) { ps[i].onclick = function() { alert(i); }
//save8: perfect solution with Let in ES6
for( let i=0; i<ps.length; i++ ) { ps[i].onclick = function() { alert(i); }