在循环初始化语句中声明变量
今天看书看到下面几句话:
《深入理解ES6》 第一章,块级作用域绑定,第9页循环中的let
声明一节中提到
《JavaScript高级程序设计(第4版)》 第三章,语言基础,3.3.2节,第28页中也提到
最佳实践
for
循环中推荐使用let
来声明迭代变量for...in
和for...of
推荐使用const
来声明迭代变量。
光看有点不好理解为什么这么设计,写点代码来实践一下。
代码实践
1. 异步打印
for (var i = 0; i < 3; ++i) {
setTimeout(() => {console.log(i)})
}
输出 3 3 3
原因:由于var
声明会进行变量提升。函数指向全局作用域的i
,打印i
的时候,i
的值已经变成3
了。
改成let试试
for (let i = 0; i < 3; ++i) {
setTimeout(() => {console.log(i)})
}
输出 0 1 2
原因:每次循环迭代都会在其块级作用域中创建一个新变量i
。
异曲同工的ES5写法
for (var i = 0; i < 3; ++i) {
(function (i){
setTimeout(() => {console.log(i)})
}(i))
}
输出 0 1 2
原因:利用闭包,人为做了一次i
的拷贝。
2. 在循环中创建函数
var fns = []
for (var i = 0; i < 3; ++i) {
fns.push(() => { console.log(i) })
}
fns.forEach(fn => fn())
输出 3 3 3
原因:由于var
声明会进行变量提升。函数使用全局作用域的同一个i
,打印i
的时候,i
的值已经变成3
了。
改成let试试
var fns = []
for (let i = 0; i < 3; ++i) {
fns.push(() => { console.log(i) })
}
fns.forEach(fn => fn())
输出 0 1 2
原因:let
每轮循环都创建了一个新的变量i
,三个函数指向了三个不同的i
。
异曲同工的ES5写法
var fns = []
for (var i = 0; i < 3; ++i) {
(function (i) {
fns.push(() => { console.log(i) })
}(i))
}
fns.forEach(fn => fn())
输出 0 1 2
原因:利用函数作用域的特点,每次循环都人为拷贝了变量i
。
使用引用类型变量进行循环
for (const i = {a: 0}; i.a < 3; i.a = i.a + 1) {
i[`${i.a}`] = i.a
setTimeout(() => console.log(i), 1000 * i.a)
}
// { '0': 0, '1': 1, '2': 2, a: 3 }
// { '0': 0, '1': 1, '2': 2, a: 3 }
// { '0': 0, '1': 1, '2': 2, a: 3 }
原因:每轮循环中,JavaScript引擎拷贝的i
实际上是一个指向堆内存对象的地址。
因为这里只是改变了堆内存对象属性的值,并没有改变i
的值(实际上i
是一个指向堆内存对象的指针),可以使用const
来声明i
,这与使用let
、var
结果相同。
如果JavaScript
提供了查看变量栈内存地址的API,那么验证这种说法就轻而易举了。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!