变量声明
根据变量声明的位置和关键字,定义值的类型、作用域、存储期属性。
:::info
变量声明理解为确定变量的类型,这样就可以知道对变量进行哪些操作。
:::
隐式声明(未限定标识符)
在javascript中提供标识符的隐式声明行为,在编译时不会发生引用错误。标识符会被自动添加global对象中。但是在严格模式下,隐式声明报错。
'use strict'
a = 2;
console.log(a);
//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对象中的属性仍然是全局的。
//如果不特殊指定全局环境,先访问的是全局变量,然后再访问window对象中的全局属性。
window.a = 1;
console.log(a); //1
let a = 2;
console.log(a); //2,既然都是全局环境,为什么不是1?说明这两个全局环境是有嵌套关系的。
参考
https://stackoverflow.com/questions/40685277/what-is-the-purpose-of-the-script-scope