有如下场景,一开始学习的人会很迷惑,为何每次都是输出 5 ?如果我想要点击弹出依次对应的数字怎么处理?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>测试一</p>
<p>测试二</p>
<p>测试三</p>
<p>测试四</p>
<p>测试五</p>
<script>
var pList = document.getElementsByTagName('p');
for(var i = 0; i<pList.length;i++){
pList[i].onclick = function(){
alert(i);
}
}
</script>
</body>
</html>
这是因为 pList 中的每一项的 onclick 均为一个函数实例(Function 对象),这个函数实例产生了一个作用域。
由于作用域链的关系,这个作用域引用了外部作用域的变量,其 function scope 的 closure 对象有个名为 i 的引用,外部作用域的变量内容发生变化,内部作用域得到的值自然会发生改变。
解决1:将变量 i 保存给在每个段落对象(p)上
var pList = document.getElementsByTagName('p');
for(var i = 0; i<pList.length;i++){
pList[i].i = i;
pList[i].onclick = function(){
alert(this.i);
}
}
解决2:使用闭包,i以函数参数的形式传递给内层函数
for(var i = 0;i<pList.length;i++){
(function(count){
pList[i].onclick= function(){
alert(count);
}
})(i)
}
解决3:es6 的 let 直接可以解决,但是有兼容性问题
for(let i = 0; i<pList.length;i++){
pList[i].onclick = function(){
alert(i);
}
}