ES6新语法之---块作用域let/const(2)

前言:

  ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了,这节学习掌握ES6中的let/const。

  1.JavaScript中的作用域

    1>函数作用域

      JavaScript中变量作用域的基本单元一直是函数(function)

<script>
    // 此处的a在{}中声明赋值
    if (true) {
        var a = 3
        console.log(a)  //打印3
    }
    console.log(a)  //打印3

    // JavaScript中函数是变量作用域的基本单元
    function fn2() {
        var b = "5";
        console.log(b); //打印5
    }
    fn2();
    console.log(b);//会报错 Uncaught ReferenceError: b is not defined
</script>

     2>"真假"块作用域

      除了JavaScript外的很多编程语言都支持块作用域(比如:项目中使用的java)

     举例:"假"块作用域

      我们在for循环的头部定义了变量i,通常是只想在for循环内部的上下文中使用i,但最后我们却可以在for之外访问到它,这样就造成了i对整个函数作用域的污染。

 for (var i = 0; i < 10; i++) {
        console.log(i)
 }
 console.log(i)  //打印出10

    举例:"真"块作用域

      JavaScript的ES3规范中规定try/catch中的catch分句会创建一个块作用域,其中声明的变量仅在catch内部有效。

<script>
    try {
        undefined() //执行一个非法操作来强制制造一个异常
    } catch (error) {
        console.log(err)    //能够正常执行,err仅在catch的作用域中有效
    }
    console.log()   //ReferenceError: err is not defined
</script>

  

  2.ES6中的let

    ES6引入了新的let关键字,提供le除var以外的另一种变量声明方式。let关键字可以将变量绑定到所在的任意作用域中。

    1>let声明的变量只在当前代码块有效

{
    let a = 10;
    var b = 1;
}
console.log(a) // ReferenceError: a is not defined
console.log(b) // 1

 

    2>let在for循环中的使用

let funcs = [];
for (let i = 0; i< 5; i++) {
    funcs.push(function () {
        console.log(i)
    });
}
funcs[3]();    //打印结果是3

    上例中,for循环头部的let i 不只为for循环本身声明了一个i,而是为循环的每一次迭代都声明了一个新的变量i,这样数组成员中变量i都是独立唯一的。

var funcs = [];
// 此处用var声明了全局变量i
for (var i = 0; i< 5; i++) {
    funcs.push(function () {
        //此处的i指向的就是全局变量i
        console.log(i)
    });
}
funcs[3](); 5//最后数组成员中的i指向都是同一个全局变量i

    上例中,for循环头部的var i 声明了一个全局变量,数组成员中变量i指向的都是同一个全局变量

 

    3>不存在变量提升

      var声明的变量会发生变量提升现象,既在变量声明之前可以对变量进行访问,结果是'undefined'

      let声明归属于块作用域,但是直到在块中出现才会初始化。

{
      console.log(a);   //undefined
      console.log(b);   //ReferenceError
    
      var a;
      var b;
  }

      在let声明/初始化之前访问let声明的变量会导致错误,这个错误严格叫做临时死亡区(Temporal Dead Zone, TDZ)

      对于TDZ值和未声明值,typeof结果是不同的,举例:

 {
        if (typeof a === "undefined") { //条件成立,未声明变量默认为undefined
            console.log("cool");
        }

        if (typeof b === "undefined") { //ReferenceError
            //...
        }
        let b;
    }

      建议:let声明的变量最好置于当前作用域开始的位置。    

    4>不允许重复声明

      let不允许在相同的作用域中声明同一个变量,也不允许在函数内部重新声明其参数

      举例:同一个作用域

        // 报错
        function func() {
            let a = 10;
            var a = 1;
        }

        // 报错
        function func() {
            let a = 10;
            let a = 1;
        }    

      举例:声明函数参数

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

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

  3.ES6中的const

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

        {
            const a = 2;
            console.log(a);
            //const声明的常量,值不允许再改变
            a = 3;  //TypeError
        }    

    变量a的值在声明时必须显示初始化,而且之后就不允许改变

    注意:

      常量不是对这个值的限制,而是对赋值的那个变量的限制

    举例:值为复杂类型

        {
            const a = [1, 2, 3];    //此时a指向的是[1, 2, 3]的地址
            a.push(4);      //[1, 2, 3]内容发生了改变,但是对象地址本身没有改变。
            console.log(a);
            //const声明的常量,值不允许再改变
            a = 3;  //TypeError     //变量a重新赋值就会报错
        }        

    上例中,const限制是a变量本省,而非[1, 2, 3]这个数组对象。

    注意:

      1.const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针,const只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了

      2.const同样不支持变量提升

      3.const同样存在临时死亡区(TDZ)

 

posted @ 2018-04-26 09:55  诸葛不亮  阅读(207)  评论(0编辑  收藏  举报