let命令
let 声明变量,只在他所在的代码块有效
var 声明变量,在全局范围内有效
let 不会存在变量提升问题,let所声明的变量一定要在声明后使用。
var 存在变量提升,变量可以在声明之前使用,值为undefined。
let 不允许在相同作用域内,重复声明同一个变量。
-
暂时性死区
如果区块中存在let 和const 命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。
凡是在声明之前就使用使用这些变量,就会报错。
在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为 "暂时性死区"(Temporal dead zone,简称TDZ)。
暂时性死区本质为只要一进入当前作用域,所使用的变量已经存在,但是不可获取,只有等到声明变量的那一行代码出现,可以获取和使用该变量。
//sample
//在代码块外var 声明变量tmp
//在代码块内使用 let 声明变量tmp,若在声明之前使用变量tmp,即形成"暂时性死区(TDZ)"
var tmp=123
if(true){
//TDZ开始
tmp = 'abc'; //ReferenceError
console.log(tmp); //ReferenceError
let tmp;
//TDZ 结束
console.log(tmp);//undefined
tmp = 123
console.log(tmp);//123
}
-
块级作用域
ES6的块级作用域必须有大括号
ES6 允许块级作用域的任意嵌套,应避免在块级作用域内声明函数。若需要,应写成函数表达式而不是函数声明语句。具体原因
const命令
const声明一个只读的常量,一旦声明,常量的值就不能改变。
const 的作用域与let命令相同:只在声明所在的块级作用域内有效。
const 声明的常量也不提升,同样存在暂时性死区。
const 实际上保证的并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。
对于简单类型的数据(数值,字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。
但对于复合类型的数据(对象、数组)变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向一个固定的地址)。但他所指向的数据结构可以发生改变
//声明一个foo常量对象,常量foo在内存中储存的是一个地址。不可变的是地址
//不能将foo指向另一个地址,但对象本身是可变的,依然可以添加新属性
const foo = {}
//为foo添加一个属性.
foo.prop = 123
console.log(foo.prop) //123
//将foo指向另一个对象,就会报错
foo = {}; //TypeError: "foo" is read-only
//若想要对象冻结,应该使用 Object.freeze()方法
const foo = Object.freeze({});
//常规模式下,下面一行不起作用
//严格模式下('use strict'),会报错。
foo.prop = 123;
//除了将对象本身冻结,对象的属性也应该冻结。下面是一个将对象彻底冻结的函数
var constantize =(obj)=>{
Object.freeze(obj);
Object.keys(obj).forEach((key,i)=>{
if(typeof obj[key] === 'object'){
constantize(obj[key]);
}
})
}
-
顶层对象的属性
顶层对象,在浏览器环境指的是 window 对象,在Node指的是global对象。
在ES5中,顶层对象的属性与全局变量是等价的。
ES6中 一方面规定 为保持兼容性,var 命令和function命令声明的全局变量,依旧是顶层对象的属性。
另一方面规定,let 、const 、class 命令声明的全局变量,不属于顶层对象的属性。
-
globalThis对象
JavaScript 语言存在一个顶层对象,他提供全局环境(即全局作用域)。所有代码都是在这个环境中运行。
但是顶层对象在各个环境的实现是不统一的。
- 浏览器中顶层对象是window,但Node 和Web Worker 没有window
- 浏览器和Web Worker里面,self 也指向顶层对象,但是Node 没有self
- Node里面,顶层对象是global,但其他环境不支持。
为同一段代码能够在各种环境,都能取到顶层对象,现在一般使用 this 变量,但有一定的局限性
- 全局环境中,this 会返回顶层对象。但是Node 模块和ES6模块中,this 返回的是当前模块
- 函数里面的this,如果函数不是作为对象的方法运行,而是单纯作为函数运行,this 会指向顶层对象。但是严格模式下,这时this 会返回undefined
- 不管是严格模式还是普通模式下,new Function('return this')(),总是会返回全局对象。但是,如果浏览器用了CSP(Content Security Policy),eval、new Function 这些方法都可能无法使用。
综上所述很难找到一种方法,在所有情况下,都取到顶层对象。
所以引入 globalThis 作为顶层对象。在任何环境下,globalThis 都是存在的,都可以从他拿到顶层对象,指向全局环境下的this