1.let变量声明—作用与var关键字类似
let关键字的几个特点:
不能重复声明同一个变量;
let a
= 1;
let a
= 1;
不存在变量提升;
console
.log(b
);
let b
= 1;
用let声明的变量仅在块级作用域下有效;
for(let i
= 0 ; i
< 5 ; i
++){
}
console
.log(i
);
不会影响作用域链;
let a
= "王宝鸡";
function test() {
console
.log(a
);
}
test();
暂时性死区;
什么是暂时性死区?===>只要块级作用域中存在let命令,let所声明的变量就绑定到了该区域,不再受到外部的影响;
var test
= 1;
{
let a
;
console
.log(a
);
}
在存在let关键字的代码块内,在使用let声明变量之前,该变量都是不可用的,这在语法上称为“暂时性死区”;
简单理解:在存在let或const关键字的作用域内,变量都必须在let声明之后再使用;
if (true) {
tmp
= 'abc';
console
.log(tmp
);
let tmp
;
console
.log(tmp
);
tmp
= 123;
console
.log(tmp
);
}
2.块级作用域
为什么要使用块级作用域?
ES5只有全局作用域和函数作用域,以下场景下任意出错:
1.内层变量覆盖外层变量2.for循环中的循环变量变成全局变量;
var temp
= 1;
function test(){
console
.log(temp
);
if(true){
var temp
= "hello world"
}
}
test();
ES6中的块级作用域:
可以任意嵌套;
{{{{let a
= 0 ;}}}}
外层作用域无法读取内层作用域中的变量;
{
let a
= 1;
{
let b
= 2;
console
.log(a
);
}
console
.log(b
);
}
内层作用域可以定义外层作用域中的同名变量;
{
let aa
= 1;
{
let aa
= 2;
console
.log(aa
);
}
}
块级作用域和函数声明:
ES5规定函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明;ES6中引入了块级作用域,并规定可以在块级作用域中声明函数,在块级作用域中声明的函数,类似于let声明的变量,函数外部是无法调用的;为了避免出错,在作用域中需要声明函数时,尽量使用函数表达式的形式,不要使用函数声明的方式;
function f() { console
.log('I am outside!'); }
(function () {
if (false) {
function f() { console
.log('I am inside!'); }
}
f();
}());
function f() { console
.log('I am outside!'); }
(function () {
var f
= undefined
;
if (false) {
function f() { console
.log('I am inside!'); }
}
f();
}());
do表达式
作用:块级作用域是一个语句,将多个表达式封装在一起,没有返回值,使用do表达式能让块级作用域成为表达式,进而拥有返回值;用法:在块级作用域前加上do;
let x
= do {
let t
= f();
t
* t
+ 1;
};
3.const命令
基本用法:
const关键字用于声明一个常量,一旦声明就不能再修改;const关键字声明的常量被声明之后需要立即初始化,否则会报错;作用域与let相同,仅在所在的块级作用域内有效;同样存在暂时性死区;不可以重复声明同一变量;
本质:
本质上来说,const保证的并不是值不允许改变,而是保证变量的内存地址不改变;对于简单数据类型来说,const保证数据与变量是相等的,但对于复杂数据类型来说,const常量中保存的仅仅是一个指向该常量的一个指针,只能保证该指针不会变化,并无法保证指针指向的数据结构不发生变化;
const obj
= {};
obj
.name
= "peanut";
console
.log(obj
.name
);
obj
= new Object();
上述代码表明,const声明的复杂类型数据中,不可变的只是那个指向对象的地址,对象本身是可以改变的;解决办法:Object.freeze()方法该方法用于冻结对象及其所有的属性;
var testObj
= Object
.freeze({
name
: "peanut",
age
: 18
})
testObj
.gender
= "male";
testObj
.name
= "andy";
console
.log(testObj
);
声明变量的6种方法(包含ES5):
1.var 2.function 3.let 4.const 5.import 6.class
4.顶层对象的属性
顶层对象在浏览器环境下指的是window对象;Node环境下指的是global对象;在es5中,顶层对象的属性与全局变量是等价的;es5中的var、function声明的变量仍会成为window对象的属性;let、const、class声明的变量不会成为window对象的属性;
var a
= 111;
let b
= 222;
console
.log(window
.a
);
console
.log(window
.b
);
global对象
ES5的顶层对象,本身也是一个问题,因为它在各种实现里面是不统一的。浏览器里面,顶层对象是window,但 Node 和 Web Worker 没有window。浏览器和 Web Worker 里面,self也指向顶层对象,但是Node没有self。Node 里面,顶层对象是global,但其他环境都不支持。
因此,在不同环境下拿到顶层对象很难有统一的方法;
解决办法:在语言标准的层面,引入global作为顶层对象。也就是说,在所有环境下,global都是存在的,都可以从它拿到顶层对象。使用垫片库(https://github.com/es-shims/globalThis))可以在所有环境下拿到global对象;