let理解:
- let 声明的变量支持块级作用域
- let 不存在变量提升
- let 存在暂时死区(不能在初始化之前,使用变量)
根据下面代码块深入理解:
(涉及块级作用域、变量提升相关知识)
// 代码段1
var liLists = document.querySelectorAll('li') // 共5个li
for( var i=0; i<liLists.length; i++){
liLists[i].onclick = function(){
console.log(i)
}
}众所周知最后 i 的打印结果都是5,而不是想象中的0、1、2、3、4
原因(仅个人理解,哪里有错误望各位大神指正):
- onclick事件触发的函数,并非立即执行,当执行时,for循环一定已经遍历完了。
- 那么很多人就有疑问: 遍历完后,
i应该是4, 可结果为什么是5,因为var存在变量提升,你应该把上面的代码这样理解:
// 代码段2
var liLists;
var i;
liLists = document.querySelectorAll('li') // 共5个li
for( i=0; i<liLists.length; i++){
liLists[i].onclick = function(){
console.log(i)
}
}- 当遍历到最后(也就是很多人理解的
i为4时),i依旧执行了最后一次i++, 只是没有满足for循环的遍历条件, 且没有进入到for循环。 但是经过变量提升后的的i已经变成了5。 - 最后当onclick时间发生的时候,所调用的函数中引用了
i变量,这个时候就涉及到了作用域,当自身作用域中找不到该变量时,就会去上一层找,上一层也找不到就会去全局中。全局的i为5, 所以结果都为5
解决的办法:
1. var改为let后, 依次触发事件, 所得到的结果为0,1,2,3,4
// 代码段3
var liLists = document.querySelectorAll('li') // 共5个li
for( let i=0; i<liLists.length; i++){
liLists[i].onclick = function(){
console.log(i)
}
}-
let声明的变量不存在变量提升 -
for( let i = 0; i< 5; i++)这句话的圆括号之间,有一个隐藏的作用域 -
for( let i = 0; i< 5; i++) { 循环体 }在每次执行循环体之前,JS 引擎会把i在循环体的上下文中重新声明及初始化一次。
也就是说上面的代码段3可以近似近似近似地理解为
// 代码段4
var liLists = document.querySelectorAll('li') // 共5个li
for( let i=0; i<liLists.length; i++){
let i = 隐藏作用域中的i // 看这里看这里看这里
liLists[i].onclick = function(){
console.log(i)
}
}那样的话,5 次循环,就会有 5 个不同的 i,console.log 出来的 i 当然也是不同的值。
2. 使用 立即执行函数+闭包
function demo(){
let arr =[]
for(var i = 1; i<=3 ; i++){
arr.push(
(function(n) {
return function(){
return n
}
})(i)
)
}
return arr
}
console.log(demo()[1]());- 这样当遍历时,
i就会被及时的留存,这里面就应用到了 闭包+立即执行函数
以上内容均借鉴于以下文章, 小编只是融合了一小部分自己的理解。
















