-
Notifications
You must be signed in to change notification settings - Fork 45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Day17 - let是否会造成变量提升 #60
Comments
总结: |
let 不会造成变量提升 |
首先上述代码不会输出 暂时性死区
|
结论不会 原因变量的声明需要经过binding和initialize两步,完成后才能正常使用。 对于let声明,binding结束并没有赋予默认值。 所以binding完成了,并不代表initial完成,initial出错并不代表,binding会回滚。 但对于var声明,默认是赋予undefine 的值 对于变量表达式,规范有要求变量必须初始化才能使用。 |
结论,会变量提升,只是和var的表现不一样,因为TDZ的作用,只是抛出了ReferenceError错误 以上面解说来看,以let/const声明的变量,的确也是有提升(hoist)的作用。这个是很容易被误解的地方,实际上以let/const声明的变量也是会有提升(hoist)的作用。提升是JS语言中对于变量声明的基本特性,只是因为TDZ的作用,并不会像使用var来声明变量,只是会得到undefined而已,现在则是会直接抛出ReferenceError错误,而且很明显的这是一个在运行期间才会出现的错误。 |
let是会造成变量提升的
|
回答不会造成变量提升 展开
暂时性死区暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量 参考https://es6.ruanyifeng.com/#docs/let#%E6%9A%82%E6%97%B6%E6%80%A7%E6%AD%BB%E5%8C%BA |
答:看定义的角度 从变量能否使用的角度:不存在。 从语言解析的角度:存在。 由于TDZ,我们常规使用let定义变量不能在定义前使用,输出报错是 VM539:1 Uncaught ReferenceError: Cannot access 'a' before initialization 不能在定义前使用变量 而直接输出不定义,则提示 VM552:1 Uncaught ReferenceError: a is not defined a未定义,因此实际上,在编译的时候,代码其实是知道已经存在a这个变量的,因此是会提升。 |
会造成变量提升。变量提升是 JavaScript 的设计造成的,是语言的特性。let 和 const 只是增加了暂时性死区,并没有改变变量提升的本质。这里变量提升理解为在代码执行到声明语句 let ,const ,var 之前,这个变量就已经存在了。变量分为创建,初始化,赋值三个阶段,变量会被收集到词法环境里,var 会在创建的时候就初始化为undefined,而 let 在创建的时候没有进行初始化undefined,而是执行到赋值的时候同时进行初始化和赋值。而没有初始化的变量读取的时候会报错 "无法在初始化之前使用" , 这个阶段就是 let 的暂时性死区。
|
|
let 的创建过程被提升了,但是初始化没有提升 所以,声明提升是变量在作用域顶层处注册和初始化耦合的结果。然而let的注册和初始化阶段是解耦的,这就使得声明提升对let无效。这种解耦造成了变量无法被引用的时间死区 |
if (true) {
a = 2; // ReferenceError;
let a = 3;
} 为了理解方便,可以将上述代码拆分成如下几步: if (true) {
// 此时a的创建已经被提升到了if代码块内的顶部(TDZ的开始)
a = 2; // 此时对a进行赋值,由于a仅仅被创建,还没有初始化,所以会报错ReferenceError
let a; // 完成a的初始化(TDZ的结束)
a = 3; // 完成对a的赋值操作。
} 而let从创建被提升到初始化这中间的部分,就是我们平常所说的暂时性死区(TDZ),即在暂时性死区中该变量都是不可用的。 |
不会被提升,let声明的变量会存在暂时性死区,在声明之前调用会抛出错误,如果外层作用域中有同名变量,也不会去访问,因为js 使用的是词法作用域,在词法分析阶段会绑定访问的变量 |
如果变量提升意味着预解析(pre parser), |
let关键字跟var很相似,但他的作用域是块级的,严格来讲,let在JavaScript运行时中也会被提升,但由于暂时性死区的缘故,实际上不能在声明之前使用let变量,因此,let的提升跟var是不一样的 |
要搞清楚提升的本质,JS 变量的「创建create、初始化initialize 和赋值assign」 |
let会造成变量提升。 |
|
let会造成变量提升。 |
let造成的暂时性死区的原因是因为:
然后就导致了上面那个问题 |
var 与 let 的 提升是不一样的。严格来讲 let 的提升只是提升了创建阶段,此时还不能被访问。如果冒然的访问会抛出错误 ReferenceError。而 var 的提升由于var的创建阶段与初始化阶段合二为一了直接进入赋值阶段可是访问的。 |
对于js引擎预编译来说,let声明会提升声明,用来开辟内存空间,用来判断是否重名或者是否未初始化调用该变量, 还有用来实现暂时性死区 |
是有提升的,准确来说,
声明函数s的时候,即使没有执行函数内部表达式,依旧会报错重复声明。 |
let会造成变量提升
|
let会造成变量提升首先明确一下变量提升的概念:变量提升是指当我们在执行到定义变量的这行代码之前,该变量就已经在内存中存在了 如果访问一个未定义的变量时,所报的错是
如果在 let 定义变量之前访问该变量,所报的错是
所以,从结果来看,在使用 let 定义变量确实存在变量提升,只是由于暂时性死区的原因,我们无法访问到当前的变量 |
let不会造成变量提升,但是js引擎在let声明语句之前是能感知到它的存在的,只是无法正常访问而已。 首先我们得明确变量提升的含义。变量提升是指,变量在声明之前可以访问并且不报错。对于var申明的变量来说,这个过程是因为执行上下文在创建的过程中会扫描变量,var创建的变量放到变量环境并给一个初始化值undefined,所以我们可以在申明语句之前访问这个变量,并且值为undefined。 console.log(a); undefined
var a = 0; 那么对于let和const来说,在执行上下文创建阶段,也会被扫描到,但是会被放入词法环境,并且不会初始化。而且这时候很重的一点,从块级作用域的开始到这条申明语句的区域,会成为一个“暂时性死区”(temporal dead zone),如果在这个区域内访问该变量,会报referrenceError。这也就导致我们不能在申明语句之前去正常访问一个let和const申明的变量。 console.log(a); // referrenceError: can't access xxx before initialization
let a = 0; 但是这里很有趣的一点就是,这里报的错是referrenceError: can't access xxx before initialization而不是 referrenceError: xx is not defined。这说明此时js引擎是能直到这个变量的存在的,但由于该变量未初始化,导致这里是暂时性死区,所以报了这个不一样的错。 |
通常意义上,我们所说的提升指的是这个变量是否被初始化了;基于这种理解,var 定义的变量存在提升,而let 定义的变量不存在提升,所以在let 给变量赋值之前,变量都是不能够被使用的,这个位置也被称为let定义变量的暂时性死区; 但是在从变量的创建到赋值再到被引用的过程中,var 定义的变量的创建和赋值都会被提升到其被引用位置的前面,所以在未执行到其被创建的代码行的位置时,打印的变量的值是undefined;而let定义的变量只有创建过程被提升到其被引用的位置的前面,而赋值过程没有同时被提升,因此在未执行到其被创建的代码行的位置时,打印变量的值会报语法错误,并表示其在被初始化之前是不能够被引用的,这也就是暂时性死区的由来;但是let 定义的变量的创建过程的提升,只存在于块级作用域之内,当其在被定义的块级作用域之外引用的话,就会报未定义; es6 文档中所提到的 let 不存在变量提升,也只是基于变量的初始化,而不是变量的创建。 |
如何解释上述代码
The text was updated successfully, but these errors were encountered: