变量声明

根据变量声明的位置和关键字,定义值的类型、作用域、存储期属性。
变量声明 - 图1 :::info 变量声明理解为确定变量的类型,这样就可以知道对变量进行哪些操作。 :::

隐式声明(未限定标识符)

在javascript中提供标识符的隐式声明行为,在编译时不会发生引用错误。标识符会被自动添加global对象中。但是在严格模式下,隐式声明报错。

  1. 'use strict'
  2. a = 2;
  3. console.log(a);
  4. //Uncaught ReferenceError: a is not defined

:::info 在C语言中隐式声明是不可以的,并且容易出错。随着语言的成熟,javascript的严格模式,提供禁用它的选项。 :::

暂时性死区

从块区域开始到let变量声明位置的区域,标识符都不能声明,包括var声明的同名变量也会失效。
理解程序进入任何作用域中,首先都会实例化词法环境,收集提升标识符,变量会自动赋值undefined。但是let和const声明的变量也被提升收集,不被允许自动赋值(这里解释了为什么var声明的同名变量也会失效?),而是等到执行到声明的位置,才被允许赋值。

global对象属性和全局环境中的变量

global对象的属性与全局变量挂钩,被认为是 JavaScript 语言最大的设计败笔之一。这样的设计带来了很大的问题:

  • var在全局声明的变量会成为全局对象的属性。但是global对象作为内置对象,不应该被程序员随意的读写修改。
  • 如果程序员声明了相同的全局对象中的属性,全局属性会被修改,很容易导致出错。

ES6 为了改变这一点,一方面为了保持兼容性,var和function声明的全局变量,依旧是global对象的属性;另一方面规定,let、const声明的全局变量,不再属于global对象的属性。也就是说,从 ES6 开始,全局环境中的变量将与global对象的属性脱钩。function声明的全局变量依旧没有改变,但是可以在模块作用域里面声明函数,就不会成为global对象的属性。

最终结果是V8引擎的控制台中有两个全局环境global和script,但是在逻辑上算作一个全局环境,只不过程序员声明的全局变量,放到另外一个全局环境里面,不再是global对象的属性,当然global对象中的属性仍然是全局的。

  1. //如果不特殊指定全局环境,先访问的是全局变量,然后再访问window对象中的全局属性。
  2. window.a = 1;
  3. console.log(a); //1
  4. let a = 2;
  5. console.log(a); //2,既然都是全局环境,为什么不是1?说明这两个全局环境是有嵌套关系的。

参考

https://stackoverflow.com/questions/40685277/what-is-the-purpose-of-the-script-scope