JS在回顾过去之后知道了新的变量提升和时间死区
前言
开始执行脚本时,执行脚本的第一步是编译代码,然后开始执行代码,如图所示
另外,在编译优化方面,并不是所有的脚本都是一开始就编译的,而是只有在函数执行的时候才会先编译后执行,如图
编译阶段:经历了词法分析、语法分析生成AST、代码生成。在这个阶段,它只会扫描提取环境中声明的变量,声明函数以便准备分配内存,所有的函数声明和变量声明都会被添加到名为词法环境的JavaScript内部数据结构中的内存中。因此,它们可以在源代码中实际声明之前使用。但是,Javascript只在内存中存储函数声明和变量声明,而不存储它们的值。执行阶段:给变量X赋值,先问内存有没有变量X,如果有,给变量X赋值,如果没有,创建变量X并赋值。可变促销
如下图所示,左边的灰色块区域是执行演示功能之前的编译阶段。首先提取所有声明的变量和声明的函数,并执行内存分配。然后开始执行代码。执行第一行代码时,如果内存中存在变量A,直接给变量A赋值.当执行到第二行时,变量b不在内存中,所以变量b将被创建并赋值。
词法环境是包含标识符变量映射的数据结构
逻辑环境={identifier : value,identifier : function object}简而言之,逻辑环境是程序执行过程中变量和函数存在的地方。
让,常量变量
console.log(a)让a=3;输出
未定义引用错误: a
所以let和const变量不会被提升?
答案会更复杂。所有声明(函数、var、let、const和class)都将在JavaScript中升级。但是,var声明由未定义的值初始化,但是let和const声明的值仍然未初始化。
它们只有在Javascript引擎运行期间执行词法绑定时才会被初始化。这意味着,在引擎声明变量在源代码中的位置并计算其值之前,您无法访问该变量。这就是我们所说的时间死区,即一个变量从创建到初始化之间的时间,我们无法访问这个变量。
如果JavaScript引擎在声明let或const的行中仍然找不到它们的值,它将为它们分配一个未定义的值或返回一个错误值(在const的情况下,它将返回一个错误值)。
6a 9a 50532 BF 60 f 5 fac6b 3c . png】(evernote cid ://f2bca3b 5-CC5A-4eb 3-BD61-DD 865800 f 342/appyingxiangcom/10369121/ENResource/p 1163)
让一个;console . log(a);//输出undefineda=5;在编译阶段,JavaScript引擎会遇到变量A,并将其存储在词法环境中,但因为它是一个let变量,所以引擎不会为它初始化任何值。因此,在编译阶段,词法环境看起来如下。
//编译阶段词法环境={a:uninitialized}现在如果我们在声明这个变量之前尝试访问它,JavaScript引擎会尝试从词法环境中获取这个变量的值,因为这个变量没有初始化,会抛出一个引用错误。
在执行过程中,当引擎到达变量声明的行时,它将尝试执行其绑定,因为变量没有与之关联的值,所以它将为其分配未定义的值
//在词典环境={a:undefined}的执行阶段后,未定义会打印到控制台,然后将5的值赋给变量a,将词典环境中变量a的值从未定义更新为5
function n foo(){ console . log(a)}让a=20foo();function foo(){ console . log(a)://referenceerror : a未定义} foo();设a=20
类别声明
像let和const声明一样,类将在JavaScript中升级,像let和const一样,它们在执行之前将保持未初始化状态。因此,它们也受到临时交易区的影响。例如
让彼得=新人('彼得',25);//ReferenceError: Person未定义console . log(Peter);类Person {构造函数(名称,年龄){ this.name=namethis.age=年龄;}}所以要访问类,必须先声明它
类Person {构造函数(名称,年龄){ this.name=namethis.age=年龄;}}let peter=new Person('Peter ',25);console . log(Peter);//person {name :' Peter ',age : 25}所以在编译阶段,上面代码的词法环境会如下:
词法环境={person: uninitialized}当引擎执行类声明时,它将使用该值初始化类。
词法环境={person: personobject}升级类表达式
让彼得=新人('彼得',25);console . log(Peter);let Person=class { constructor(name,age){ this . name=name;this.age=年龄;} }
让彼得=新人('彼得',25);console . log(Peter);var Person=class { constructor(name,age){ this . name=name;this.age=年龄;} }
所以现在我们知道我们的代码在升级过程中实际上并没有被JavaScript引擎移动。正确理解晋升机制,有助于避免日后因因变量晋升而产生的任何错误和混乱。为了避免像未定义的变量或引用错误这样的副作用,总是尝试在它们各自的作用域顶部声明变量,并且总是尝试在声明变量时初始化它们。
现代JavaScript中的提升——让、常量和变量
摘要
以上就是本文的全部内容。希望本文的内容对大家的学习或工作有一定的参考价值。有问题可以留言交流。谢谢你的支持。
版权声明:JS在回顾过去之后知道了新的变量提升和时间死区是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。