02.let和const命令

    科技2022-07-16  149

    1.let变量声明—作用与var关键字类似

    let关键字的几个特点:

    不能重复声明同一个变量; let a = 1; let a = 1; // 抛出错误 Identifier 'a' has already been declared 不存在变量提升; console.log(b); let b = 1; // 抛出错误,不存在变量提升 Cannot access 'b' before initialization 用let声明的变量仅在块级作用域下有效; // 3.仅在块级作用域下有效 for(let i = 0 ; i < 5 ; i++){ // console.log(i); } console.log(i); //报错,i未定义 不会影响作用域链; // 4.不影响作用域链 let a = "王宝鸡"; function test() { console.log(a); } test();// 王宝鸡 ,说明作用域链不受影响,仍会从函数外部查找变量 暂时性死区;

    什么是暂时性死区?===>只要块级作用域中存在let命令,let所声明的变量就绑定到了该区域,不再受到外部的影响;

    // 不受外部影响 var test = 1; { let a; console.log(a); // undefined }

    在存在let关键字的代码块内,在使用let声明变量之前,该变量都是不可用的,这在语法上称为“暂时性死区”;

    简单理解:在存在let或const关键字的作用域内,变量都必须在let声明之后再使用;

    if (true) { // TDZ开始 tmp = 'abc'; // ReferenceError console.log(tmp); // ReferenceError let tmp; // TDZ结束 console.log(tmp); // undefined tmp = 123; console.log(tmp); // 123 }

    2.块级作用域

    为什么要使用块级作用域?

    ES5只有全局作用域和函数作用域,以下场景下任意出错: 1.内层变量覆盖外层变量2.for循环中的循环变量变成全局变量; // 场景1:内层变量覆盖外层变量 var temp = 1; function test(){ console.log(temp); if(true){ var temp = "hello world" } } test(); // undefined 内层temp变量由于变量提升,成为外层中一个未初始化的变量

    ES6中的块级作用域:

    可以任意嵌套; {{{{let a = 0 ;}}}} 外层作用域无法读取内层作用域中的变量; // 外层作用域无法访问内层作用域中的变量 { let a = 1; { let b = 2; console.log(a); // 1 .内层可以访问外层 } console.log(b); // b is not defined 外层无法访问内层 } 内层作用域可以定义外层作用域中的同名变量; { let aa = 1; { let aa = 2; console.log(aa); // 2 内层可以修改外层的同名变量 } }

    块级作用域和函数声明:

    ES5规定函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明;ES6中引入了块级作用域,并规定可以在块级作用域中声明函数,在块级作用域中声明的函数,类似于let声明的变量,函数外部是无法调用的;为了避免出错,在作用域中需要声明函数时,尽量使用函数表达式的形式,不要使用函数声明的方式; // ES6的浏览器环境 function f() { console.log('I am outside!'); } (function () { if (false) { // 重复声明一次函数f function f() { console.log('I am inside!'); } } f(); }());// Uncaught TypeError: f is not a function // ES6的浏览器环境 上述代码的执行过程 function f() { console.log('I am outside!'); } (function () { var f = undefined; // 函数提升,但是函数声明不会随着函数提升到作用域顶部 if (false) { function f() { console.log('I am inside!'); } } f(); }()); // Uncaught TypeError: f is not a function

    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); // "peanut" 可以对const声明的对象添加属性 obj = new Object(); // Assignment to constant variable. 将obj指向新的对象会报错 上述代码表明,const声明的复杂类型数据中,不可变的只是那个指向对象的地址,对象本身是可以改变的;解决办法:Object.freeze()方法该方法用于冻结对象及其所有的属性; // 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对象的属性; // 在es5中,顶层对象的属性与全局变量是等价的 // es5中的var、function声明的变量仍会成为window对象的属性 // let、const、class声明的变量不会成为window对象的属性 var a = 111; let b = 222; console.log(window.a); // 111 console.log(window.b); // undefined

    global对象

    ES5的顶层对象,本身也是一个问题,因为它在各种实现里面是不统一的。浏览器里面,顶层对象是window,但 Node 和 Web Worker 没有window。浏览器和 Web Worker 里面,self也指向顶层对象,但是Node没有self。Node 里面,顶层对象是global,但其他环境都不支持。

    因此,在不同环境下拿到顶层对象很难有统一的方法;

    解决办法:在语言标准的层面,引入global作为顶层对象。也就是说,在所有环境下,global都是存在的,都可以从它拿到顶层对象。使用垫片库(https://github.com/es-shims/globalThis))可以在所有环境下拿到global对象;
    Processed: 0.014, SQL: 8