第 27 题:关于 const 和 let 声明的变量不在 window 上
在ES5中,顶层对象的属性和全局变量是等价的,var 命令和 function 命令声明的全局变量,自然也是顶层对象。
var a = 12;
function f(){};
console.log(window.a); // 12
console.log(window.f); // f(){}
但ES6规定,var 命令和 function 命令声明的全局变量,依旧是顶层对象的属性,但 let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。
let aa = 1;
const bb = 2;
console.log(window.aa); // undefined
console.log(window.bb); // undefined
在哪里?怎么获取?通过在设置断点,看看浏览器是怎么处理的:
通过上图也可以看到,在全局作用域中,用 let 和 const 声明的全局变量并没有在全局对象中,只是一个块级作用域(Script)中
怎么获取?在定义变量的块级作用域中就能获取啊,既然不属于顶层对象,那就不加 window(global)呗。
let aa = 1;
const bb = 2;
console.log(aa); // 1
console.log(bb); // 2
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(16)
根据以上的讨论,我也补充下。
如下创造了2个Block,分别对应变量e和f;1个Script(也可以理解为顶级Block),对应变量a和b,剩下的c和d作为全局变量。
继续补充一下函数和try catch的,五种应该全了
scope作用域链
关于这道题题解,发现答案没有从根本上解释全局环境下声明的let和const 为什么没有挂在window对象 上面???
其实关于这道题我们需要了解全局环境与全局执行上下文的相关概念后,才能解释为什么是这样
关于相关概念我们需要参阅ECMA规范 https://www.ecma-international.org/ecma-262/6.0/
GlobalEnv是一个复合环境,包括一个由global构成的对象环境(objEnv)和一个一般声明的环境(declsEnv)组合而成,它是双环境组成的,统一交付一个环境存取的界面(objEnv/declsEnv 对应 Global/Script)
let/const 声明会放在declsEnv里面,而var的变量会通过ObjEnv来声明, 所以显而易见说明,let,const 声明的变量不在window对象
其实这里还有很多内容可以展开讨论
关于环境概念也可参考的的笔记
关于答案更权威解释和更多可以展开内容的讨论 参考极客时间
同意 XiaoDHuang 的解答。
要想知道为什么 const 和 let 声明的变量不在 window 上,理解 ECMAScript 文档中的 environment record概念即可。细节可以看我个人整理的知识点 《一起读ECMAScript-ECMAScript 中是如何讲解 environment record 和 executing context 的》
另外,最高赞答案说“全局环境下通过 let 和 const 声明变量处于script块级作用域中“,这句话概念上肯定是不正确的。没有理解 TC39 成员是如何在向后兼容 ES5 的情况下引入块级作用域的。
要想理解 ES6 引入的块级作用域只需要看看 ECMAScript 当中是如何解释 for 循环的。《ECMAScript 是如何通过 declaration 识别 block scope的》
那么如何在 global 环境中获取?
直接通过 identifier 获取就可以,只是没有被绑定在 global object 上。原理是 resolve binding 仍然可以通过 global execution context 指向的 lexical environment record 中的 declarative environment record 获取。
在定义变量的块级作用域中就能获取
class、let定义的即便是全局对象,但不是顶层对象的属性,在window自然获取不到,只能去定义变量的块级作用域里获取
var的创建和初始化被提升,赋值不会被提升;
let的创建被提升,初始化和赋值不会被提升;
function的创建、初始化和赋值均会被提升;
我开始以为这个let和const以及var不难,当我真正去尝试深入的时候发现涉及到一个全新的概念:script作用域。我理解他是我认为他和window是同级的作用域,他们共存的,但是一直有一个东西困扰我就是,这个script作用域是怎么来的?是在script脚本开始执行时就和window一样被创建了?可当我没有写任何代码就debugger的时候,我发现他并不存在,只有全局window的存在。当我尝试使用const和let时,他们便被创建出来了!同时我又去验证了一件事情,我在一个块作用域下去创建一个变量,如果我使用var,那么这个变量依然在全局,但是当我使用const或let时,他会创建一个全新的块作用域,并将这些变量放到这个块作用域下。所以我总结了一下:
感兴趣的可以自行去浏览器控制台的源代码那块点作用域去测试。
const和let会生成块级作用域,可以理解为
ES5没有块级作用域的概念,只有函数作用域,可以近似理解成这样。
所以外层window必然无法访问。
我同时还想补充一点的就是如果在声明之前调用let const 声明的变量的时候会报错(这里面有一个暂时性死区的问题)不能再声明之前调用
例如:
与之相比var let const三种,前者因为var的变量会提升到window,但是let个const不会,let ,const会生成块作用域,同一作用域下let和const不能声明同名变量,而var可以
你这个相当于 是块作用域了,没有在全局作用域中
在ES5中,全局变量直接挂载到全局对象的属性上,所以能在window上看到var声明的变量
在ES6中,全局对象的属性和全局变量脱钩,但是为了保持兼容性,旧的不变,所以var、function声明的全局变量依然可以在window对象上看到,而let、const声明的全局变量在window对象上看不到
js的这种"绝对领域"(作用域)是通过什么创造的呢?是通过”{ }“这两个符号创造的,有代码为证:
var obj = { }
,如果上面的代码在"{ }"前面放上一个等号就会是当作对象词法解析了。