09 | 块级作用域:var缺陷以及为什么要引入let和const?
该思维导图由 AI 生成,仅供参考
作用域(scope)
- 深入了解
- 翻译
- 解释
- 总结
ES6解决了JavaScript中存在的变量提升设计缺陷,引入了块级作用域和let、const关键字。文章通过分析变量提升问题,介绍了ES6的解决方案。通过示例代码展示了let和const的用法,以及ES6如何通过块级作用域解决变量提升问题。进一步讨论了JavaScript引擎是如何同时支持变量提升和块级作用域的,通过对变量环境和词法环境的介绍,解释了JavaScript引擎的工作机制。最后,总结了语言本身的重要性,强调了语言的价值在于为开发者创造价值。文章内容深入浅出,帮助读者快速了解ES6解决变量提升问题的原理和作用。文章通过具体的示例和深入的技术讨论,帮助读者理解了ES6的解决方案,以及JavaScript引擎的工作机制,为读者提供了深入的技术知识和实际应用价值。
《浏览器工作原理与实践》,新⼈⾸单¥59
全部留言(113)
- 最新
- 精选
- coolseaman【最终打印结果】:VM6277:3 Uncaught ReferenceError: Cannot access 'myname' before initialization 【分析原因】:在块作用域内,let声明的变量被提升,但变量只是创建被提升,初始化并没有被提升,在初始化之前使用变量,就会形成一个暂时性死区。 【拓展】 var的创建和初始化被提升,赋值不会被提升。 let的创建被提升,初始化和赋值不会被提升。 function的创建、初始化和赋值均会被提升。
作者回复: 很好,这个答案大家可以参考下
2019-08-2437545 - 朙这篇真的是神作啊。 有一个疑问,在abcd那个例子里,第一步<编译并创建执行上下文>的图里并没有块级作用域的b=undefined; d=undefined。而在第二步里<继续执行代码>的图中才出现b=undefined; d=undefined。想问下这个块级作用域的b=undefined; d=undefined是不是应该在第一步的编译阶段里就有。还是说在执行阶段像函数那样,块级作用域会有一个自己的编译阶段
作者回复: 执行函数时才有进行编译,抽象语法树(AST)在进入函数阶段就生成了,并且函数内部作用域是已经明确了,所以进入块级作用域不会有编译过程,只不过通过let或者const声明的变量会在进入块级作用域的时被创建,但是在该变量没有赋值之前,引用该变量JavaScript引擎会抛出错误---这就是“暂时性死区”
2019-08-241172 - YBB有个问题,在一个块级作用域中,let和const声明的变量是在编译阶段被压入栈中还是执行阶段被压入栈中?在文中的表述来看,第一个let声明的变量是在编译阶段就压入栈中的,但是后面的变量又感觉是在执行是压入栈中,有点混乱。
作者回复: 对的,你的理解没错 函数只会在第一次执行的时候被编译,所以编译时变量环境和词法环境最顶层数据已经确定了。 当执行到块级作用域的时候,块级作用域中通过let和const申明的变量会被追加到词法环境中,当这个块执行结束之后,追加到词法作用域的内容又会销毁掉。
2019-08-26464 - Tim看得很生气,全篇文章不提变量的「创建」「初始化」「赋值」这三种区别,把创建和初始化揉在一起了,也是看了精选留言里第一条评论之后Google才查找到,否则刚开始我真的不理解为啥都已经在词法环境找到了变量却报错了!按照这种理论的话,是否说明词法环境只有变量,并没有等于undefined? 真的不需要更新一下吗?????
作者回复: 变量初始化和创建再上上一节《变量提升:JavaScript代码是按顺序执行的吗?》中已经讲过了, 我们将到了一个变量编译阶段和执行阶段分别要做那些事情。 这一节主要是将var和let的区别以及底层实现机制的,我看你的疑问是下面这个问题: function test(){ console.log(a) let a = 7; } test() 执行test的时候,编译阶段a已经在内存中,为什么提前访问不了? 这主要是因为V8虚拟机做了限制,虽然a在内存中,但是当你在let a 之前访问a时,根据ECMAScript定义,虚拟机会阻止的访问! 如果你还有其它具体的问题,欢迎继续提出!
2020-01-121155 - 晓小东在ES3开始,try /catch 分句结构中也具有块作用域。补充……
作者回复: 赞
2019-08-25327 - 李懂执行上下文是在编译时创建的,在执行代码的时候已经有词法环境了,而且变量已经默认初始化了undefiend,为什么还会存在暂时性死区,老师解答一下!
作者回复: 暂时性死去是语法规定的,也就是说虽然通过let声明的变量已经在词法环境中了,但是在没有赋值之前,访问该变量JavaScript引擎就会抛出一个错误。
2019-08-24718 - William第二步,继续执行代码。 这张图我觉得有错误,当进入foo函数内部的代码块之后,并没有了编译阶段,此时,新创建的栈顶块级作用域的内容为空,而并没有 b = undefined 和 d = undefined 两项内容。 执行完 let b = 3 之后,分配内存,块级作用域出现 b = 3 一项。 执行 let d = 5 之后,为d分配内存,栈顶块级作用域增加一项 d = 5。
作者回复: 使用let/const声明的变量,伴随着词法环境被创建,但只有在变量的词法绑定(LexicalBinding)已经被求值运算后,才能够被访问。 你也可以在let b声明之前断点下,看看scope中的值有没有,你会看scope中的值已经存在了。
2019-08-24810 - 小锅锅老师,听你对比了c语言,既然let const存在暂时性死区,那么c语言的变量也存在同样的暂时性死区报错吗?
作者回复: c语言都没这概念,因为你在定义之前使用一个变量,首先过不了c语言的编译
2019-08-257 - 朙if(0){ var myname = " 极客邦 "} 这段代码里的if条件是false很有意思。是说编译阶段不管if会不会执行。里面的代码都会编译,因此这里的myname变量提升,从而导致上面的console.log(myname)输出undefined吗? 另外let 声明的变量会提升吗?
作者回复: 对的,第一个分析的没问题 第二个let不会产生变量提升
2019-08-2427 - Geek_East我想,理解execution context和scope的区别是理解这个问题的一个关键;很多时候执行上下文和作用域都混着说
作者回复: 这是两样不同的东西,一个表示一个表示函数运行时的上下文,一个表示词法作用域! 我会在下篇介绍V8的专栏中详细分析这块内容!
2019-12-061