美文网首页
let命令和const命令的使用注意事项

let命令和const命令的使用注意事项

作者: microkof | 来源:发表于2018-01-04 18:01 被阅读38次

    本文大量参考阮一峰老师ES6手册。

    先是let的使用注意事项

    let只在所在的代码块以及更深的代码块内有效

    通常就是花括号包起来的代码块,形成的作用域叫块级作用域。

    if (true) {
        let a = 1;
        if (true) {
            a = 2;
            console.log(a); // 2
        }
        console.log(a); // 2
    }
    

    比较特别的for循环

    for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。

    所以,for (var i = 0; i < 10; i++)for (let i = 0; i < 10; i++)就有区别,下面栗子可以证明:

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

    我们知道,函数只有被调用的时候才会去考虑作用域,而且js的作用域特点是词法作用域,所以:

    第一段代码,打印10是因为i是全局变量,当调用a[6]的时候i就是10,所以打印10没毛病。

    第二段代码,a[6]console.log(i)会去找ii既然是由let声明,就被禁锢在for作用域内,而且for循环10次能产生10个作用域,所以i在那个作用域的值是6,于是打印6

    不变量提升

    这个特性的优点我认为是:符合人脑思维:先声明,后使用。没声明就使用的话,会报错,更醒目,程序员更容易纠错。就像下面这样:

    // var 的情况
    console.log(foo); // 输出undefined,不报错
    var foo = 2;
    
    // let 的情况
    console.log(bar); // 报错ReferenceError
    let bar = 2;
    

    要我说,其实这个特性没什么大用。尽早声明变量应该是写代码的起码规范。

    “暂时性死区”(temporal dead zone,简称 TDZ)

    这个现象是老外提出来的,但我并没有看出它跟“不变量提升”有什么区别。死区的原因不就是“变量不提升”+“块级作用域”么?

    不变量提升也好,暂时性死区也好,都是强迫程序员写出更规范的代码,就认为是严格模式就得了。

    不允许重复声明

    这个跟var确实有鲜明对比。

    简单一句话:铜锣湾只能有一个浩南!(如果出了铜锣湾那就随便了)

    if (true) {
        let a = 1;
        if (true) {
            let a = 2;
            console.log(a); // 2
        }
        console.log(a); // 1
    }
    

    上面代码如果把两个let改成var,那么会输出两个2,就是因为var允许重复声明。

    块级作用域

    块级作用域的优点:

    1. 模块化编程。
    2. 不需要特意写一个自执行函数来制造一个局部作用域。

    到底能不能在块级作用域声明函数?

    ES5是不允许的,但是ES6又允许了。本着兼容原则,最好是别这么干,也就是不要在块级作用域声明函数。如果必须要在块代码里写函数,就用函数表达式。

    到底啥时候用var,啥时候用let?

    var和let各自的适用场合:

    1. 为了兼容低版本IE,当然用var。除此之外,优先用let。
    2. 有人说,es6中用let,babel中用var,原因是babel会写很多垫片代码实现对let的支持,从代码量来讲得不偿失。

    以下是const的注意事项

    const跟let特性一致的地方

    1. 块级作用域
    2. 不提升
    3. 不可重复声明(重复声明跟再次赋值是两码事)
    4. 即使在全局作用域声明,也不会是window对象的属性

    跟let特性的区别

    就一条,let虽然不能重复声明,但是可以无限制的赋值,但const只能初始化的时候赋值一次。

    到底啥时候用let,啥时候用const?

    一句话:const永远优先原则。

    1. 在全局环境,不应该设置变量,只应设置常量。可能你有顾虑是我真的想让一个量被修改,又真的想让它在全局环境,怎么办?这种情况下,可以用这种方式:
    const globelConst = {a: 1, b: 2}; // a和b的值确实是可以改变的,原因见下文
    
    1. 在局部环境,也应该优先考虑使用const,除非它真的需要改变值,那么就用let。

    小心赋值复合类型数据

    对于简单类型的数据(数值、字符串、布尔值),const的值是绝对不会变的,因为变量指向保存在特定内存地址的数据。但对于复合类型的数据(主要是对象和数组),变量指向的是对应内存地址的指针,const只能保证这个指针是唯一的指针,至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个数组或者对象声明为常量必须非常小心。

    如果想要真正冻结一个数组或者对象,可以用Object.freeze方法。

    const foo = Object.freeze({});
    
    // 常规模式时,下面一行不起作用;
    // 严格模式时,该行会报错
    // 总之是不能用
    foo.prop = 123;
    

    但是这个方法只能浅冻结,如果想深冻结,就得写个方法:

    var deepFreeze = (obj) => {
      Object.freeze(obj);
      Object.keys(obj).forEach( (key, i) => {
        if ( typeof obj[key] === 'object' ) {
          deepFreeze( obj[key] );
        }
      });
    };
    

    相关文章

      网友评论

          本文标题:let命令和const命令的使用注意事项

          本文链接:https://www.haomeiwen.com/subject/ivornxtx.html