let和const

let命令

  • 声明的变量,只在声明的代码块中有效

  • 适用于for循环

    for(let i=0;i<10;i++){
       //声明的i只在for循环体中有效,在外面不能访问
    }
    • 如下,i递增时,已定义的数组项中的i值,不会改变,因为无法访问到循环体中的i

      • 但若i是通过var定义的,则全局都可以访问,i递增时,数组项中的i也会改变

      for (let i = 0; i < 10; i++) {
             a[i]=function () {
                 console.log(i)
            }
        }
         a[6]();

for循环中的作用域

  • for循环中,设置循环变量的部分和循环体中是两个独立的作用域

  • 若在此两个作用域中使用let定义同名变量,互不影响。但若是var定义同名变量,互相会影响

    for (let i = 0; i < 3; i++) {
       let i='看看';
       console.log(i)
    }

    //i等于0时进入循环,重新赋值为'看看',输出,继续判断i是否小于3,无法比较,停止循环
    for (var i = 0; i < 3; i++) {
       var i='看看';
       console.log(i)
    }

不存在变量提升

  • 通过var声明的变量,在声明之前,会进行预解析。同样可以调用,返回undefined

  • 但通过let声明的变量,声明之前不会预解析,不能调用

    console.log(a);//undefined
    var a = 10;
    console.log(b);//报错
    let b = 20;

暂时性死区

本质:只要以进入当前作用域,所要使用的变量就已经存在了,但是还没有声明,不可获取。只有执行到了声明该变量那一行之后,才可以获取和使用该变量。

  • 只要某个块级作用域内,使用了let声明变量,则这个变量就绑定了此块级作用域,不会被外界影响

  • 此时即使是通过var在外部声明的变量,只要通过let在块级作用域内也声明了。在块级作用域内、声明前调用,也会报错

    var a = 3;
    if (true) {
       a = 10;
       let a;
    }
  • 此时typeof不再百分百安全

    typeof tmp;//报错
    let tmp=10;
  • 以下行为也会报错

    • 赋值时,x的声明并没有完成,依然会当做没有声明处理

    let x= x;

不允许重复声明

  • let不允许在同一个作用域内重复声明同一个变量

    function func() {//报错
       let arg=20;
       var arg=10;
    }

    function func() {//报错
       let arg=20;
       let arg=10;
    }

    function func(arg) {//报错
       let arg;
    }
    func()

    function func(arg) {//不报错,不同作用域
          {
               let arg
          }
      }
       func()

块级作用域

  • let为函数新增了块级作用域

块级作用域与函数声明
  • ES5规定,函数只能在顶级作用域和函数作用域中声明,不能在块级作用域中声明

  • 浏览器没有遵守这个规定,为了兼容以前的旧代码,还是支持在块级作用域之中声明函数

  • 但在ES6浏览器中,浏览器的实现只需遵守:

    • 允许在块级作用域内声明函数。

    • 函数声明类似于var,即会提升到全局作用域或函数作用域的头部。

    • 同时,函数声明还会提升到所在的块级作用域的头部。

  • 考虑到环境问题,在块级作用域内声明函数时最好使用表达式

  • ES6的块级作用域必须有{}

 

const

  • const声明一个只读的常量,一旦声明常量的值就不能更改

  • const一旦声明变量,就必须立即初始化

  • 同样只在声明的块级作用域中有效

  • const命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用

const的本质

  • 实际上是保证声明的变量所指向的内存地址中所保存的值不能改变。

  • 对应简单的数据类型:数字、字符串等等,值就保存在变量指向的那个内存地址,等同于常量

  • 而数组、对象,因为其变量指向的地址中保存的依然是指向实际数据的指针,所以只能保证保存的指针不改变,而指针指向的实际数据可以改变,所以

    const a = [];
    a.push(1);//不报错
    console.log(a);
    a = [];//报错

冻结对象

  • 如果真的想将对象冻结,应该使用

    const foo = Object.freeze({});
    foo.prop=123;//严格模式下报错
posted @ 2020-03-24 16:26  ashen1999  阅读(103)  评论(0编辑  收藏  举报