html
<body onload="init();"> <p>产品 0</p> <p>产品 1</p> <p>产品 2</p> <p>产品 3</p> <p>产品 4</p> </body>
js
function init() { var pAry = document.getElementsByTagName("p"); for( var i=0; i<pAry.length; i++ ) { pAry[i].onclick = function() { alert(i); } } }
<!--
原因是初学者并未理解JavaScript的闭包特性。通过element.onclick=function(){alert(i);}方式给元 素添加点击事件。响应函数function(){alert(i);}中的 i 并非每次循环时对应的 i(如0,1,2,3,4)而是循环后最后 i 的值5。 或者说循环时响应函数内并未能保存对应的值 i,而是最后一次i++的值5。
了解了原因,下面就由几种方式可与解决:
-->
Javascript闭包的实现,通常是在函数内部再定义函数,让该内部函数使用上一级函数的变量或全局变量。
子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。
既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!
由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。
所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
//将变量 i 保存给在每个段落对象(p)上
function init1() { var pAry = document.getElementsByTagName("p"); for( var i=0; i<pAry.length; i++ ) { pAry[i].i = i; pAry[i].onclick = function() { alert(this.i); } } }
//将变量 i 保存在匿名函数自身
function init2() { var pAry = document.getElementsByTagName("p"); for( var i=0; i<pAry.length; i++ ) { (pAry[i].onclick = function() { alert(arguments.callee.i); }).i = i; } }
//加一层闭包,i 以函数参数形式传递给内层函数
function init3() { var pAry = document.getElementsByTagName("p"); for( var i=0; i<pAry.length; i++ ) { (function(arg){ pAry[i].onclick = function() { alert(arg); }; })(i);//调用时参数 } }
//加一层闭包,i 以局部变量形式传递给内层函数
function init4() { var pAry = document.getElementsByTagName("p"); for (var i = 0; i < pAry.length; i++) { (function() { var temp = i; //调用时局部变量 pAry[i].onclick = function() { alert(temp); } })(); } }
//加一层闭包,返回一个函数作为响应事件(注意与3的细微区别)
function init5() { var pAry = document.getElementsByTagName("p"); for (var i = 0; i < pAry.length; i++) { pAry[i].onclick = function(arg) { return function() { //返回一个函数 alert(arg); } }(i); } }
//用Function实现,实际上每产生一个函数实例就会产生一个闭包
function init6() { var pAry = document.getElementsByTagName("p"); for( var i=0; i<pAry.length; i++ ) { pAry[i].onclick = new Function("alert(" + i + ");");//new一次就产生一个函数实例 } }
//用Function实现,注意与6的区别
function init7() { var pAry = document.getElementsByTagName("p"); for (var i = 0; i < pAry.length; i++) { pAry[i].onclick = Function('alert(' + i + ')'); } }
//第二种理解闭包
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ //function是全局的,所以下面的this会指向window return this.name; }; } }; alert(object.getNameFunc()()); //The Window
//2222
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(name){ return function(){ return this.name; } }('My Object') }; alert(object.getNameFunc()); //My Object
//end