最近在研究闭包函数,看到一篇博客:闭包函数调用小记,尝试跑了一下文中的代码,有一些思考。
大家都知道闭包函数在操作循环变量时会有问题,因为内部匿名函数并非立即执行,而是在函数被引用时才会执行,所以内部函数用到的循环变量在执行的时候早就不是当初那个变量了。对于文章中的内部函数,是onfocus动作触发的函数,所以只有当鼠标聚焦到某个输入框内时,才会触发该函数,所以无论如何,该函数不会立即执行也不能立即执行,必须想办法把item跟函数先锁死。
文中对输入框问题提出了三个解决方案,但细究的话,其实还是如何将当下循环的item变量提前传入内部函数中,先绑死,等执行的时候自然就调用属于自己的循环变量了,下面逐一分析一下:
解决一:
文中这个解决方案其实不是增加一层闭包的问题,而是把闭包独立写出来,并且通过传参res将item.showcount跟闭包函数绑死,这样,即使不立即执行闭包函数,参数也已经传进去了。
解决二:
方案二与一其实本质一样,但文中代码有错,匿名函数必须传入当前的循环变量item,否则不起作用。
所以正确的代码应为:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>这是一个闭包测试</title>
</head>
<body>
<p id="showid">显示焦点元素</p>
<p>Name: <input type="text" id="name"></p>
<p>E-mail: <input type="text" id="email"></p>
<p>Age: <input type="text" id="age"></p>
<script type="text/javascript">
function setshowid() {
var Text = [
{'id': 'email', 'showcont': '正在输入邮箱'},
{'id': 'name', 'showcont': '正在输入姓名'},
{'id': 'age', 'showcont': '正在输入年龄'}
];
for (var i = 0; i < Text .length; i++) {
var item = Text [i];
(function(item){
document.getElementById(item.id).onfocus = function(){
showiddom(item.showcont);
}
})(item);
}
}
setshowid();
function showiddom(res) {
document.getElementById('showid').innerHTML = res;
}
</script>
</body>
</html>
解决三:
就是通过区分块作用域的 let 方式声明变量,也可以解决问题。