8
混乱作用域、闭包问题
source link: http://misaka.im/index.php/archives/45/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
混乱作用域、闭包问题
<button>A</button>
<button>B</button>
<button>C</button>
<button>D</button>
<p id="output"></p>
var buttons = document.querySelectorAll('button');
var output = document.querySelector('#output');
for (var i = 0; i < buttons.length; ++i) {
buttons[i].addEventListener('click', function (e) {
output.innerText = buttons[i].innerText;
}, false)
}
JavaScript
看似会正常运行的代码,居然在点击后出乎意料地报错了
Uncaught TypeError: Cannot read property 'innerText' of undefined
- Click 事件触发时
i
变量已是 4 - 循环时
i
变量存在于全局作用域 - 运行时的监听器读取循环结束后的变量
i
(4)
let 关键字
对于原来的代码,只需要改动一个地方即可,将对计数器 i 的定义从 var 改成 let,便可以在循环体内形成块级作用域,让每一次循环的执行都能保留当前计数器的数值和引用。—— 《实战 ES2015》
for (let i = 0; i < buttons.length; ++i) {
buttons[i].addEventListener('click', function (e) {
output.innerText = buttons[i].innerText;
}, false)
}
JavaScript
使用立即执行函数包裹,解决闭包问题。
for (var i = 0; i < buttons.length; i++) {
(function (index) {
buttons[i].addEventListener('click', function (e) {
output.innerText = buttons[index].innerText;
}, false)
})(i);
}
JavaScript
曲线救国
既然 i
变量有问题,为何不使用回调函数中的参数 e
,这样就可以读取按钮中文本了。
for (var i = 0; i < buttons.length; i++) {
buttons[i].addEventListener('click', function (e) {
output.innerText = e.target.innerText;
}, false)
}
JavaScript
错误的栗子
以上的代码,尝试用点击事件来说明作用域问题,使人处于一个可运行,又可能会出问题的迷茫中。
使用另外一个例子来说明
for(var i = 1; i <= 5; i++) {
setTimeout(function() {
console.log('Value of i : ' + i);
},100);
}
JavaScript
Value of i : 6
Value of i : 6
Value of i : 6
Value of i : 6
Value of i : 6
问题便显而易见,使用上面的 let 关键字 或 IIFE 即可解决这个问题。
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK