ES6 let解决的闭包问题
ES6 let
let
是 ES6 新增的命令,用来声明变量
let 用法和 var 类似,区别:
-
var 声明变量存在变量提升,let 不存在变量提升 -
var 可以重复声明变量,let 不可以重复声明 -
let 声明变量存在块作用域({} 内)
js 闭包
闭包
就是能够读取其他函数内部变量的函数。由于 js 作用域链,只有函数内部的子函数才能读取函数内部的局部变量,所以可以把闭包简单理解成”定义在一个函数内部的函数”,本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁
闭包用途:
-
使函数外部能够读取函数内部的变量 function fn() {
var num = 1
//闭包:getNum函数通过作用域链可以访问到变量num,并将其返回到fn函数外部
return function getNum() {
return num
}
}
//变量num为fn函数的局部变量,函数外面无法访问
console.log(num) //报错:num is not defined
//getNum函数作为fn函数的返回值被赋值给n,执行n返回num
var n = fn()
console.log(n()) //1 -
让函数内部变量的值始终保存在内存中 function add() {
var num = 1
//闭包:addNum函数通过作用域链可以访问到变量num,并将其的累加值返回到add函数外部
return function addNum() {
return num++
}
}
//addNum函数作为add函数的返回值被赋值给全局变量n,执行n返回num的累加值
//add函数内部引用着add函数里的变量num,所以变量num始终被保存在内存中,不会被释放
var n = add()
console.log(n()) //1
console.log(n()) //2
console.log(n()) //3
使用 let 解决的闭包问题
举例:预期输出 0 1 2 3 4
for(var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i)
}, 0)
}
实际输出:

分析:
由于 js 是单线程的,按照 js 的事件循环机制,在执行同步任务 for 循环时,异步任务 setTimeout 定时器被放到任务队列中排队等待执行,等待 for 循环执行完,此时 i 的的值已经为5,任务队列中的五个 setTimeout 开始执行,访问到的 i 的值都为5,所以打印出来五个5
问题:
全局作用域中 var 声明的变量为全局变量,每次循环 i 的值不能被保存,这就会出现闭包问题
使用立即执行函数解决:
for(var i = 0; i < 5; i++) {
(function(i) {
setTimeout(function() {
console.log(i)
}, 0)
})(i)
}
输出:

分析:
在 for 循环中,将 setTimeout 定时器放到一个立即执行函数中,将每次循环 i 的值保存到函数作用域里,作为参数传递给 setTimeout,在执行五个 setTimeout 时访问到的 i 为当前函数作用域里每次循环保存起来的 i 的值,所以打印出来0 1 2 3 4
总结:
利用函数作用域形成闭包,保存每次循环 i 的值
使用 let 解决:
for(let i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i)
}, 0)
}
输出:

分析:
将 for 循环中的 var 改为 let,这样在每次 for 循环之前都会生成一个块级作用域,每个块级作用域互不干扰,let 声明的变量 i 只在当前循环的块级作用域中有效,每一次循环的 i 都被声明为一个新的变量,在执行五个 setTimeout 定时器时访问到的 i 为当前块级作用域里声明的 i 的值,所以打印出来0 1 2 3 4
总结:
利用块级作用域形成闭包,保存每次循环 i 的值
原文始发于微信公众号(前端24):ES6 let解决的闭包问题
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/217066.html