02.let和const命令

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对象;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值