以上是一个简单例子(代码与图) 记录下容易令我回忆的理解方式 也为和我一样的初学者好理解。 js中的 for ( var i = 0; i < lis.length; i++){ (function (i) { lis[i].onclick = function (){ console.log(i); } })(i);
重点是这个定义完就调用 (function(){})(); 函数的理解 为啥传个i它就能在点击事件不是全打印成一个lis.length值呢 因为(function(){})(); 函数每次执行时都会在内存开辟一个空间,当(function(i){})(i); 这时候它就得到自己一个i了,其实这个i和for循环的i不是一个i,接着,lis[i].onclick 指向被赋的函数,但点击事件没有消失没有触发,所以当前这个(function(i){})(i);的空间不会被释放i会被保存下来,比如传个0这个空间的i就是0,当点击事件触发时,它会找i是啥值,在这个(function(){})();函数内它就会找到属于它的i,它依然还是个0 当for循环时,你以为(function(){})();新开辟的空间是上一个(function(){})();的那个空间,i值被覆盖了?不不不,它是匿名函数有个i形参且立即调用了,它每次一循环就新开辟了一个空间,i又是新的,此时的i依然是跟for循环的i值一样但本质不一样。 就是大概成下面这个图的理解(大内存套四个小内存) 而点击全打印成一个值得函数理解: 当遍历时, lis[i].onclick = function (){ console.log(i); }之后 onclick点击事件被赋予一个函数,这里的console.log(i);可以理解为未点击时该函数先存了i变量的地址,然后for循环继续,当点击触发时会去找i变量地址代表的值,但for循环的i++已经使i变成lis.length值了,所以打印全一样
以上就是利用闭包形式获得索引值出现问题的一个理解 这个用闭包比较浪费空间,上面lis[i].index生成一个index属性更方便些,代码在上面注释掉那。
综上,其实就是想让i值保存,但for循环的i值又是变换的所以(function(){})();让i一个个存了 匿名自调用,空间不覆盖; 闭包延变量,空间不消失; 点击有惊喜,变量值还在; 平常它不用,面试题有它。
其实(function(){})();和ES6新增let又有点相似的意思 let每次for循环后生成一个块级作用空间,let的i就在当前的那一个用,每次一循环一个块作用空间。这个也容易想到些
window.addEventListener('load',function(){ // 闭包 var lis = document.querySelectorAll('li'); for (let i = 0; i < lis.length; i++) { lis[i].onclick = function(){ console.log(i); }} });个人也比较喜欢用这种
