时间:2021-05-26
前言
开始执行脚本时,执行脚本的第一步是编译代码,然后再开始执行代码,如图
另外,在编译优化方面来说,最开始时也并不是全部编译好脚本,而是当函数执行时,才会先编译,再执行脚本,如图
变量提升
如下图,左边灰色块区域,是演示函数执行前的编译阶段,先抽出所有声明变量和声明函数,并进行内存分配。然后再开始执行代码,在执行第一行代码的时候,若是变量a存在于内存中,则直接给变量a赋值。而执行到第二行时,变量b并没有在内存中,则会创建变量b并给它赋值。
Lexical enviroment是一种包含标识符变量映射的数据结构
LexicalEnviroment = { Identifier: <value>, Indentifier: <function object>}简而言之,Lexical enviroment就是程序执行过程中变量和函数存在的地方。
let,const变量
输出
ReferenceError: a is not defined
所以let和const变量并不会被提升吗?
这个答案会比较复杂。所有的声明(function, var, let, const and class)在JavaScript中都会被提升,然而var声明被undefined值初始化,但是let和const声明的值仍然未被初始化。
它们仅仅只在Javascript引擎运行期间它们的词法绑定被执行在才会被初始化。这意味着引擎在源代码中声明它的位置计算其值之前,你无法访问该变量。这就是我们所说的时间死区,即变量创建和初始化之间的时间,我们无法访问该变量。
如果JavaScript引擎仍然无法在声明它们的行中找到let或者const的值,它将为它们分配undefined值或返回错误值(在const的情况下会返回错误值)。
6a9a50532bf60f5fac6b3c.png](evernotecid://F2BCA3B5-CC5A-4EB3-BD61-DD865800F342/appyinxiangcom/10369121/ENResource/p1163)
let a;console.log(a); // outputs undefineda = 5;在编译阶段,JavaScript引擎遇到变量a并将它存储在lexical enviroment,但是因为它是一个let变量,所以引擎不会为它初始化任何值。所以,在编译阶段,lexical enviroment看起来像下面这样。
// 编译阶段lexicalEnvironment = { a: <uninitialized>}现在如果我们尝试在声明它之前访问该变量,JavaScript引擎将会尝试从词法环境中拿到这个变量的值,因为这个变量未被初始化,它将抛出一个引用错误。
在执行期间,当引擎到达了变量声明的行,它将试图执行它的绑定,因为该变量没有与之关联的值,因此它将为其赋值为unedfined
// 执行阶段lexicalEnviroment = { a: undefined}之后,undefined将会被打印到控制台,然后将值5赋值给变量a,lexical enviroment中变量a的值也会从undefined更新为5
functionn foo() {console.log(a)}let a = 20;foo(); function foo() {console.log(a): // ReferenceError: a is not defined}foo();let a = 20;Class Declaration
就像let和const声明一样,class在JavaScript中也会被提升,并且和let,const一样,知道执行之前,它们都会保持uninitialized。因此它们同样会受到Temporal Deal Zone(时间死区)的影响。例如
let peter = new Person('Peter', 25); // ReferenceError: Person is not definedconsole.log(peter);class Person { constructor(name, age) { this.name = name; this.age = age; }}因此要访问class,必须先声明它
class Person { constructor(name, age) { this.name = name; this.age = age; }}let peter = new Person('Peter', 25); console.log(peter);// Person { name: 'Peter', age: 25 }所以在编译阶段,上面代码的lexical environment(词法环境)将如下所示:
lexicalEnvironment = { Person: <uninitialized>}当引擎执行class声明时,它将使用值初始化类。
lexicalEnvironment = { Person: <Person object>}提升Class Expressions
所以现在我们知道在提升过程中我们的代码并没有被JavaScript引擎实际移动。正确理解提升机制将有助于避免因变量提升而产生的任何未来错误和混乱。为了避免像未定义的变量或引用错误一样可能产生的副作用,请始终尝试将变量声明在各自作用域的顶部,并始终尝试在声明变量时初始化变量。
Hoisting in Modern JavaScript — let, const, and var
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
变量命名在《初识永远强大的函数》一文中,有一节专门讨论“取名字的学问”,就是有关变量名称的问题,本温故而知新的原则,这里要复习:名称格式:(下划线或者字母)+(
温故而知新,可以为师矣,有空经常复习一下基础知识是有必要的,并且能加深理解和记忆。Foreach常用于循环访问集合,对实现IEnumerable的接口的容器进行
温故而知新,可以为湿矣 首先请大家记住这个V8的在线手册——http://izs.me/v8-docs/main.html。 还记得上次的building.
js中针对数组操作的方法还是比较多的,今天突然想到来总结一下,也算是温故而知新吧。不过不会针对每个方法进行讲解,我只是选择其中的一些来讲。首先来讲一下push和
有的时候,你在编程进入一定阶段,进一步提升很困难的境况之下,不妨回过头来看看基础的东西,或许你会有新的受益,或许能够真正的体会到孔夫子所谓的“温故而知新”的真正