Repository navigation
ES6 系列之 let 和 const #82
Description
Activity
哈,还是先写了 ES6 ,手动 DOGE。
Reacted by iew2018, sailing_boat and Cheng HuangReacted by mumiao, 冴羽, Idealv, Li-saltair, win, Path, D, michaelChe, teddy1209, Alisazheng12345 and 3 moreReacted by Alisazheng12345- 写的很不错…On Mon, May 21, 2018 at 5:59 PM BeijiYang ***@***.***> wrote: 哈,还是先写了 ES6 ,手动 DOGE。 — You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub <#82 (comment)>, or mute the thread <https://github.com/notifications/unsubscribe-auth/AB212IEY7zdOT5R-HRXTU5ECl7wuAbZOks5t0pARgaJpZM4UGXxM> .
期待V8源码系列已经很久了,我的大刀已经饥渴难耐了!
Reacted by wangshujun-wsj, Mr.Jason, cobish, mumiao, yyhappynice, 流浪的先知, 御风, baiyuze, daiwiy, bubbleTg and 5 morefor (var i = 0; i < 3; i++) { var i = 'abc'; console.log(i); } // abc
这里为什么会只输出一个abc呢??求教
@brushbird
'abc' ++ --> NaN
NAN<3 --->False
循环退出Reacted by Damer Wang, web_hl, levi, mumiao, Linbubin, 冴羽, 是雪碧啊, YanMuXin, Hello Lee, 成为大牛的男人 and 93 moreReacted by xiaojueji, Yuushigure and 见微Reacted by 冴羽, 宝宝宝 and 柒陌非常赞。
@BeijiYang 写完 ES6 系列,等我写 React 系列的时候,就可以尽情的使用 ES6 的语法 (๑•̀ㅂ•́)و✧
@CharlyCheng 这个……不是想让你伤心……但我没有说过写 V8 系列……
Reacted by Path, blackHeart and Jia@shadowprompt @thisisandy @horizon0514 @JChermy 感谢你们,送上致意 o(////▽////)q
let 在 for 循环中创建的隐藏作用域,以及babel模拟创建函数作用域,用以保存i的值,让我印象深刻呀。以前只知道for循环中let可以解决var变量问题,现在知道原理了
Reacted by Xeonnn我就是来刷刷存在感滴
@brushbird 'abc'<3 -> false
Reacted by 御风, XiaoJG and yangrui博主有个问题不太理解~
for (let i = 0; i < 3; i++) { let i = 'abc'; console.log(i); }
babel 编译后为
for (var i = 0; i < 3; i++) { var i = "abc"; console.log(i); }
这快我有点不理解 编译前后的代码 执行行为应该是一致的 现在却不一致.@lzy68187311 你确定编译后是这个样子?应该不是吧
49 remaining items
@617429782 在for循环里有特殊处理,可以搜一下知乎方应杭的写的一篇文章,名字我记得大概是终于理解了let
react啥时候出大佬
for (var i = 0; i < 3; i++) { var i = 'abc'; console.log(i); } // abc
这里为什么会只输出一个abc呢??求教
var i=abc
你说呢请问一下,tdz具体是个啥东西,是会专门开辟一段内存去储存let const这些吗
块级作用域存在于 “块中(字符 { 和 } 之间的区域)”, 这句怎么理解呀
function init () {
console.log('init called');
return Math.random();
}for (let i = 0, j = init(); i < 100; i++) {
console.log(i);
console.log(j);
}// 最后输出的j都是完全一样的,for循环的第一段变量声明应该只会执行一次,但是会单独开辟一个块级作用域
解决了之前一些模棱两可的问题,感谢~
for (var i = 0; i < 3; i++) { var i = 'abc'; console.log(i); } // abc
这里为什么会只输出一个abc呢??求教
因为i在第一次执行之后,被改写成了‘abc’,不符合后续循环条件了
- 邮件已收到,祝一切安好~
- 这是来自QQ邮箱的假期自动回复邮件。你好,你的邮件我收到,谢谢。
关于临死性死区最近有碰到一个问题,仔细研究了一下,let 和 const 也是会存在提升的,只是他提升之后的值并不是基础数据类型,而是内部定义的
uninitialized,当访问到的值为该值时抛出错误。- 这是来自QQ邮箱的假期自动回复邮件。你好,你的邮件我收到,谢谢。
- 邮件已收到,祝一切安好~
- 您好!您的邮件已收到,我会尽快查收!若有急事请拨打我的电话:13668913609(663609)谢谢!
块级作用域的出现
通过 var 声明的变量存在变量提升的特性:
初学者可能会觉得只有 condition 为 true 的时候,才会创建 value,如果 condition 为 false,结果应该是报错,然而因为变量提升的原因,代码相当于:
如果 condition 为 false,结果会是 undefined。
除此之外,在 for 循环中:
即便循环已经结束了,我们依然可以访问 i 的值。
为了加强对变量生命周期的控制,ECMAScript 6 引入了块级作用域。
块级作用域存在于:
let 和 const
块级声明用于声明在指定块的作用域之外无法访问的变量。
let 和 const 都是块级声明的一种。
我们来回顾下 let 和 const 的特点:
1.不会被提升
2.重复声明报错
3.不绑定全局作用域
当在全局作用域中使用 var 声明的时候,会创建一个新的全局变量作为全局对象的属性。
然而 let 和 const 不会:
再来说下 let 和 const 的区别:
const 用于声明常量,其值一旦被设定不能再被修改,否则会报错。
值得一提的是:const 声明不允许修改绑定,但允许修改值。这意味着当用 const 声明对象时:
临时死区
临时死区(Temporal Dead Zone),简写为 TDZ。
let 和 const 声明的变量不会被提升到作用域顶部,如果在声明之前访问这些变量,会导致报错:
这是因为 JavaScript 引擎在扫描代码发现变量声明时,要么将它们提升到作用域顶部(遇到 var 声明),要么将声明放在 TDZ 中(遇到 let 和 const 声明)。访问 TDZ 中的变量会触发运行时错误。只有执行过变量声明语句后,变量才会从 TDZ 中移出,然后方可访问。
看似很好理解,不保证你不犯错:
两个例子中,结果并不会打印 "global",而是报错
Uncaught ReferenceError: value is not defined,就是因为 TDZ 的缘故。循环中的块级作用域
一个老生常谈的面试题,解决方案如下:
ES6 的 let 为这个问题提供了新的解决方法:
问题在于,上面讲了 let 不提升,不能重复声明,不能绑定全局作用域等等特性,可是为什么在这里就能正确打印出 i 值呢?
如果是不重复声明,在循环第二次的时候,又用 let 声明了 i,应该报错呀,就算因为某种原因,重复声明不报错,一遍一遍迭代,i 的值最终还是应该是 3 呀,还有人说 for 循环的
设置循环变量的那部分是一个单独的作用域,就比如:
这个例子是对的,如果我们把 let 改成 var 呢?
为什么结果就不一样了呢,如果有单独的作用域,结果应该是相同的呀……
如果要追究这个问题,就要抛弃掉之前所讲的这些特性!这是因为 let 声明在循环内部的行为是标准中专门定义的,不一定就与 let 的不提升特性有关,其实,在早期的 let 实现中就不包含这一行为。
我们查看 ECMAScript 规范第 13.7.4.7 节:
我们会发现,在 for 循环中使用 let 和 var,底层会使用不同的处理方式。
那么当使用 let 的时候底层到底是怎么做的呢?
简单的来说,就是在
for (let i = 0; i < 3; i++)中,即圆括号之内建立一个隐藏的作用域,这就可以解释为什么:然后每次迭代循环时都创建一个新变量,并以之前迭代中同名变量的值将其初始化。这样对于下面这样一段代码
就相当于:
当执行函数的时候,根据词法作用域就可以找到正确的值,其实你也可以理解为 let 声明模仿了闭包的做法来简化循环过程。
循环中的 let 和 const
不过到这里还没有结束,如果我们把 let 改成 const 呢?
结果会是报错,因为虽然我们每次都创建了一个新的变量,然而我们却在迭代中尝试修改 const 的值,所以最终会报错。
说完了普通的 for 循环,我们还有 for in 循环呢~
那下面的结果是什么呢?
结果是 'c';
那如果把 var 改成 let 或者 const 呢?
使用 let,结果自然会是 'a',const 呢? 报错还是 'a'?
结果是正确打印 'a',这是因为在 for in 循环中,每次迭代不会修改已有的绑定,而是会创建一个新的绑定。
Babel
在 Babel 中是如何编译 let 和 const 的呢?我们来看看编译后的代码:
编译为:
我们可以看到 Babel 直接将 let 编译成了 var,如果是这样的话,那么我们来写个例子:
如果还是直接编译成 var,打印的结果肯定是 undefined,然而 Babel 很聪明,它编译成了:
我们再写个直观的例子:
本质是一样的,就是改变量名,使内外层的变量名称不一样。
那像 const 的修改值时报错,以及重复声明报错怎么实现的呢?
其实就是在编译的时候直接给你报错……
那循环中的 let 声明呢?
Babel 巧妙的编译成了:
最佳实践
在我们开发的时候,可能认为应该默认使用 let 而不是 var ,这种情况下,对于需要写保护的变量要使用 const。然而另一种做法日益普及:默认使用 const,只有当确实需要改变变量的值的时候才使用 let。这是因为大部分的变量的值在初始化后不应再改变,而预料之外的变量之的改变是很多 bug 的源头。
ES6 系列
ES6 系列目录地址:https://github.com/mqyqingfeng/Blog
ES6 系列预计写二十篇左右,旨在加深 ES6 部分知识点的理解,重点讲解块级作用域、标签模板、箭头函数、Symbol、Set、Map 以及 Promise 的模拟实现、模块加载方案、异步处理等内容。
如果有错误或者不严谨的地方,请务必给予指正,十分感谢。如果喜欢或者有所启发,欢迎star,对作者也是一种鼓励。