第 27 题:关于 const 和 let 声明的变量不在 window 上

发布于 2022-07-12 13:41:01 字数 1032 浏览 1105 评论 16

在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

在哪里?怎么获取?通过在设置断点,看看浏览器是怎么处理的:

letandconst

通过上图也可以看到,在全局作用域中,用 let 和 const 声明的全局变量并没有在全局对象中,只是一个块级作用域(Script)中

怎么获取?在定义变量的块级作用域中就能获取啊,既然不属于顶层对象,那就不加 window(global)呗。

let aa = 1;
const bb = 2;

console.log(aa); // 1
console.log(bb); // 2

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

与风相奔跑 2022-05-04 13:57:23

根据以上的讨论,我也补充下。
如下创造了2个Block,分别对应变量e和f1个Script(也可以理解为顶级Block),对应变量a和b,剩下的c和d作为全局变量
const和let的作用域

江心雾 2022-05-04 13:57:23

继续补充一下函数和try catch的,五种应该全了
2

岁月静好 2022-05-04 13:57:23

scope作用域链

风启觞 2022-05-04 13:57:23

关于这道题题解,发现答案没有从根本上解释全局环境下声明的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对象

其实这里还有很多内容可以展开讨论

  • 关于执行上下文的lexicalEnvironment 和 VariableEnviroment指向
  • 关于环境与执行上下文的关系
  • 关于eval('var x = 0;let y = 0') 执行上下文的lexicalEnvironment和VariableEnviroment指向问题

关于环境概念也可参考的的笔记

关于答案更权威解释和更多可以展开内容的讨论 参考极客时间

关于从前 2022-05-04 13:57:23

同意 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 获取。

情定在深秋 2022-05-04 13:57:23

在定义变量的块级作用域中就能获取

木落 2022-05-04 13:57:23

class、let定义的即便是全局对象,但不是顶层对象的属性,在window自然获取不到,只能去定义变量的块级作用域里获取

葬花如无物 2022-05-04 13:57:23

var的创建和初始化被提升,赋值不会被提升;
let的创建被提升,初始化和赋值不会被提升;
function的创建、初始化和赋值均会被提升;

寒冷纷飞旳雪 2022-05-04 13:57:23

我开始以为这个let和const以及var不难,当我真正去尝试深入的时候发现涉及到一个全新的概念:script作用域。我理解他是我认为他和window是同级的作用域,他们共存的,但是一直有一个东西困扰我就是,这个script作用域是怎么来的?是在script脚本开始执行时就和window一样被创建了?可当我没有写任何代码就debugger的时候,我发现他并不存在,只有全局window的存在。当我尝试使用const和let时,他们便被创建出来了!同时我又去验证了一件事情,我在一个块作用域下去创建一个变量,如果我使用var,那么这个变量依然在全局,但是当我使用const或let时,他会创建一个全新的块作用域,并将这些变量放到这个块作用域下。所以我总结了一下:

  1. script作用域是块作用域的全局,就像全局作用域和函数作用域之间的关系。他们非常相似,只是一个是全局,一个是局部。
  2. 同时script作用域的特性和块作用域一样,如果内部没有let和const定义,作用域便不会被创建出来。
    debugger
    var a = 'window a'

    debugger
    const b = 'script b'
    debugger
    {
      const c = 'Block c'
      debugger
    }
    function Fun() {
      const a = 'Fun a'
      var b = 'Fun b'
      debugger
    }
    Fun()

感兴趣的可以自行去浏览器控制台的源代码那块点作用域去测试。

梦行七里 2022-05-04 13:57:07

const和let会生成块级作用域,可以理解为

let a = 10;
const b = 20;
相当于:
(function(){
         var  a = 10;
         var b = 20;
})()

ES5没有块级作用域的概念,只有函数作用域,可以近似理解成这样。
所以外层window必然无法访问。

演多会厌 2022-05-04 13:56:33

我同时还想补充一点的就是如果在声明之前调用let const 声明的变量的时候会报错(这里面有一个暂时性死区的问题)不能再声明之前调用
例如:

console.log(a); //Uncaught ReferenceError: Cannot access 'a' before initialization
let a = 1;
鹿港小镇 2022-05-04 13:55:58

与之相比var let const三种,前者因为var的变量会提升到window,但是let个const不会,let ,const会生成块作用域,同一作用域下let和const不能声明同名变量,而var可以

与他有关 2022-05-04 13:52:04

js的这种"绝对领域"(作用域)是通过什么创造的呢?是通过”{ }“这两个符号创造的,有代码为证:

  let a = 1;
  {
    let aa = 20;
    console.log(aa); // 20
  }

  console.log(a); // 
  console.log(aa); // Uncaught ReferenceError: aa is not defined
  • 注意:这里的”{ }“要区分对象的写法var obj = { },如果上面的代码在"{ }"前面放上一个等号就会是当作对象词法解析了。

你这个相当于 是块作用域了,没有在全局作用域中

一曲爱恨情仇 2022-05-04 13:47:08

在ES5中,全局变量直接挂载到全局对象的属性上,所以能在window上看到var声明的变量
在ES6中,全局对象的属性和全局变量脱钩,但是为了保持兼容性,旧的不变,所以var、function声明的全局变量依然可以在window对象上看到,而let、const声明的全局变量在window对象上看不到

荒芜了季节。 2022-05-04 11:00:44

js的这种"绝对领域"(作用域)是通过什么创造的呢?是通过”{ }“这两个符号创造的,有代码为证:

  let a = 1;
  {
    let aa = 20;
    console.log(aa); // 20
  }

  console.log(a); // 
  console.log(aa); // Uncaught ReferenceError: aa is not defined
  • 注意:这里的”{ }“要区分对象的写法var obj = { },如果上面的代码在"{ }"前面放上一个等号就会是当作对象词法解析了。
~没有更多了~

关于作者

半寸时光

暂无简介

0 文章
0 评论
23 人气
更多

推荐作者

lioqio

文章 0 评论 0

Single

文章 0 评论 0

禾厶谷欠

文章 0 评论 0

alipaysp_2zg8elfGgC

文章 0 评论 0

qq_N6d4X7

文章 0 评论 0

放低过去

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文