我一直在跟踪一个示例代码,以演示JavaScript闭包的行为,但是解释不充分(或者至少我不理解该解释)。我希望有人向我解释以下代码为什么会如此表现,我已经花了好几个小时了。
本教程提供了一个行为异常的初始示例,该示例通过使用闭包来解决。
HTML文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Closures</title>
</head>
<body>
<h1 class="closures"></h1>
<ol>
<li class="track">track 1</li>
<li class="track">track 2</li>
<li class="track">track 3</li>
<li class="track">track 4</li>
<li class="track">track 5</li>
<li class="track">track 6</li>
<li class="track">track 7</li>
<li class="track">track 8</li>
<li class="track">track 9</li>
<li class="track">track 10</li>
</ol>
<script src="closure.js"></script>
</body>
</html>
使用以下JavaScript:
var elNumber = document.getElementById('number');
function setupClickHandlers(){
var tracks = document.getElementsByClassName('track');
function clickHandler(){
console.log(i);
}
for (var i = 1; tracks.length + 1; i++){
tracks[i].addEventListener("click",clickHandler);
}
}
setupClickHandlers();
预期的行为应该是当您单击每个轨道li
元素时,控制台应记录该轨道的编号。很简单!
它最初通过var循环遍历每个轨道,将clickHandler()
作为回调传递,这只是将值i
记录到控制台。
但是,结果不正确,因为var循环运行得太快,导致每个轨道将10
记录到控制台。我了解这是因为在var循环完成且i
达到10
的值之后,clickHandler会触发
为解决此问题,对新功能setupClickHandlers()
进行了如下修改:
function setupClickHandlers(){
var tracks = document.getElementsByClassName('track');
function generateClickHandler(i){
return function clickHandler(i){
return console.log(i);
}
}
for (var i = 0; tracks.length; i++){
tracks[i].addEventListener("click",generateClickHandler(i));
}
}
i
现在作为参数传递到generateClickHandler(i)
中,在那里函数返回到事件侦听器,从而解决了问题。
我只是不知道为什么这样做,返回回调函数是否意味着循环等待?为什么初始示例的行为方式不同?希望有人可以帮忙...