JS闭包

问题1:闭包

考虑下面的代码:

var nodes = document.getElementsByTagName(‘button‘);
for (var i = 0; i < nodes.length; i++) {
   nodes[i].addEventListener(‘click‘, function() {
      console.log(‘You clicked element #‘ + i);
   });
}

 

请问,如果用户点击第一个和第四个按钮,控制台上会输出什么?为什么?

答案

上面代码的目的在于检测JavaScript的一个重要概念:闭包。对于每一个JavaScript开发者来说,如果你想在网页中编写5行以上的代码,那么准确理解和恰当使用闭包是非常重要的。如果你想开始学习或者只是想简单地温习一下闭包,那么我强烈建议你去阅读这个教程:Colin Ihrig 写的JavaScript Closures Demystified 。

好了,回到上面的代码。控制台会输出两次You clicked element #NODES_LENGTH,其中#NODES_LENGTH等于nodes的结点个数。由于闭包中变量的值不是静态的,i的值并不是添加click事件处理器时的值(比如,当给第一个button添加click事件处理器时i为0,给第二个添加时i为1)。当for循环结束时,变量i的值等于nodes的长度。因此事件被执行时,控制台会输出变量i当前的值,即等于nodes的长度。

问题2:闭包

修复上题的问题,使得点击第一个按钮时输出0,点击第二个按钮时输出1。

答案

有多种办法解决这个问题,下面我给出其中的两种。

第一个解决方案要用到一个IIFE来创建另外一个闭包,从而得到所希望的i的值。相应的代码如下:

var nodes = document.getElementsByTagName(‘button‘);
for (var i = 0; i < nodes.length; i++) {
   nodes[i].addEventListener(‘click‘, (function(i) {
      return function() {
         console.log(‘You clicked element #‘ + i);
      }
   })(i));
}

 

另一个解决方案不使用IIFE,而是将函数移到循环的外面,代码如下:

function handlerWrapper(i) {
   return function() {
      console.log(‘You clicked element #‘ + i);
   }
}
 
var nodes = document.getElementsByTagName(‘button‘);
for (var i = 0; i <nodes.length; i++) {
   nodes[i].addEventListener(‘click‘, handlerWrapper(i));
}

 

来源:http://web.jobbole.com/81785/

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。