ES6 之 let和const命令

let命令特点

  • let 声明的变量只在其所在的代码块有效

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

    # demo2
    for (let i = 0; i< 10;i++){}
    console.log(i); //ReferenceError: i is not defined

    # demo3
    var a = [];
    for(var i = 0; i< 10;i++){
        a[i] = function () {
            console.log(i);
        }
    }
    a[6]();     //10
    上述代码,i是var声明,作用于全局变量,每循环一次,新的i值都会覆盖旧值,导致最后输出的都最后一轮的i值

    # demo4
    var a = [];
    for(let i = 0; i< 10;i++){
        a[i] = function () {
            console.log(i);
        }
    }
    a[6]();     //6
    上述代码,i是let声明,声明的变量仅在块级作用域中有效,当前i只在本轮循环中有效,所以每次循环的i都是一个新的变量,最后将输出6

  • 不存在变量提升
    console.log(foo);       //undefined
    let foo = 2;

    console.log(typeof x);  //undefined
    let x;

    上述代码中,let不像var一样发生‘变量提升’现象,so,变量一定要在声明后使用,否则会报错。

    ps: 自己亲测的时候,并没有出现ReferenceError,只是打印出来了undefined,
        书籍上记载为报错,这块存在疑义。
  • 暂时性死区
    # demo1
    var temp = 123;
    if(true) {
        temp = 'abc';
        let temp;
        console.log(temp);  //undefined
    }

    ps: 只要块级区域内存在let命令,它所声明的变量就‘绑定’在该区域,不再受外界影响
        S6 明确规定,如果区块中存在letconst命令,这个区块对这些命令声明的变量,
        从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
        总之,代码块中使用let命令声明变量之前,该变量不可用,语法称为‘暂时性死区’


    # demo2    
    if(true){
        temp = 'abc';   
        console.log(temp); // 亲测:abc         书上:ReferenceError

        let temp;
        console.log(temp); //亲测:undefined   书上:undefined

        temp  = '123';
        console.log(temp); // 亲测:123         书上:123        

    }

    ps: 上述代码,在let声明之前,都属于temp的‘死区’    


    # demo3
    # 有些‘死区’较为隐蔽,不易发现
    function bar(x = y, y = 2) {
        return [x,y];
    }
    console.log(bar());     // 亲测: [ undefined, 2 ]   书上:报错

    ps:bar函数报错,参数x默认值等于参数y,此时的参数y并没有声明,属于‘死区’


    function bar(x = 2, y = x) {
        return [x, y];

    }
    console.log(bar());         // 亲测:[2, 2]  书上:[2, 2]


    总结:暂时性死区的本质为,只要进入当前作用域,所要使用的变量就已经存在,但是不可以获取,
         只有等声明变量那行代码出现,才可以获取和使用该变量。

-不允许重复声明

    // 亲测:报错 Duplicate declaration "a"
    function b() {
        let a = 10;
        var a = 1;
    }

    // 亲测:报错 Duplicate declaration "a"
    function b() {
        let a = 10;
        let a = 1;
    }

    //亲测:报错  Duplicate declaration "args"
    function func(args) {
        let args;
    }

    //亲测:不报错
    function func(args) {
        {
            let args;
        }
    }

    ps:不能在函数内部重新声明参数

const命令

  • const 用来声明常量,一旦声明,其值就不能改变
    # demo1
    const PI = 301415;

    PI = 3;     

    //  亲测 报错:"PI" is read-only

    # demo2
    const foo;
    // SyntaxError: Missing initializer in const declaration
    //const而言,只声明不赋值就会报错
  • 不存在变量提升

    if (true) {
        const MAX = 5;
    }
    console.log(MAX); 
    // Uncaught ReferenceError: MAX is not defined
    ps: const的作用域与let命令相同:只在声明所在的块级作用域内有效。
  • 暂时性死区
    if (true) {
        console.log(MAX);   // 亲测: undefined    书上:ReferenceError
        const MAX = 5;
    }
    ps: const命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。
  • 不允许重新声明
    var message = "Hello!";
    let age = 25;

    const message = "Goodbye!";
    const age = 30;
    ps: 会报错,const也不可以重复声明常量
  • 复合类型的变量,变量名不指向数据,而是指向数据所在的地址,
    # demo1
    const foo = {}
    foo.prop = 123;
    console.log(foo.prop);  //123
    foo = {}                // "foo" is read-only
    ps: 上面代码中,常量foo储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,
         即不能把foo指向另一个地址,   但对象本身是可变的,所以依然可以为其添加新属性。


    # demo2
    const a = [];
    a.push('luopangpang');
    console.log(a);         //[ 'luopangpang' ]
    a.length = 0;   
    console.log(a);         // []
    ps: 上面代码中,常量a是一个数组,这个数组本身是可写的,但是如果将另一个数组赋值给a,就会报错。


    # 对象冻结,应该使用Object.freeze方法
    const foo = Object.freeze({});
    // 常规模式时,下面一行不起作用, 严格模式时,该行会报错
    foo.prop = 123;
    ps: 上述代码中,常量foo指向一个冻结的对象,所以添加新属性不起作用,严格模式时还会报错。

    # 对象本身冻结,对象的属性也应该冻结
    var constantize = (obj) => {
      Object.freeze(obj);
      Object.keys(obj).forEach( (key, i) => {
        if ( typeof obj[key] === 'object' ) {
          constantize( obj[key] );
        }
      });
    };

跨模块常量

    //myModule.js
    export const A = 1;
    export const B = 2;
    export const C = 3;

    //test1.js
    import * as constants from './myModule.js';
    console.log(constants.A);   //1
    console.log(constants.B);   //2

    //test2.js
    import {A,B} from './myModule.js';
    console.log(A);   //1
    console.log(B);   //2

全局对象的属性

全局对象是最顶层的对象
浏览器环境: window对象
Node.js:global对象
ES5中,全局对象的属性与全局变量是等价的

    window.a = 1;
    console.log(a);         //1
    a = 2;
    console.log(window.a);  //2

    ps: 全局对象的属性与全局变量的赋值是同一件事,
        ES5中var命令和function命令声明的全局变量依旧为全局对象的属性
        ES6中let命令、const命令、class命令声明的全局变量不属于全局对象的属性

    var a = 1;
    //假设在Node.js的REPL环境,可以写成global.a 或者 采用通用的方法,写成this.a
    window.a      //1

    let b = 2;
    window.b;     //undefined

块级作用域

  • 场景一: 内层变量可能覆盖外层变量
    var temp = new Date();
    function f() {
        console.log(temp);  //undefined
        if (false){
            var temp = 'hello world';
        }
    }
    console.log(f());       //undefined

    ps: 变量提升导致内层的temp变量覆盖外层变量
  • 场景二: 用作计数循环变量泄漏为全局变量
    var a = [1,2,3,4,5];
    for(var i = 0 ; i<a.length;i++ ){
        console.log(a[i]);      //5
    }
    console.log(i);             //5

ES6新增了块级作用域

    function f1() {
        let n = 5;
        if(true){
            let n = 10;
        }
        console.log(n); //5
    }
    ps: 外层代码块不受内层代码块影响,最终输出5,假设为var命令声明,最终输出为10

ES6规定,函数本身的作用域在其所在的块级作用域之内


    function f() {
        console.log("我在外面");
    }

    (function () {

        if (false) {
            // 重新声明
            function f() {
                console.log("我在里面");
            }
        }
        f();        //我在外面
    }());

    ps: ES5结果为 ‘我在里面’,原因为变量提升,不过进不进人到if中,函数声明都会提升到当前作用域的顶部而执行
        ES6支持块级作用域,不管是否进入if,其内部声明的函数都不会影响外部。



    {
        let a  = 123;
        function f(){
            return a;
        }

    }

    f();  //ReferenceError: f is not defined

    ps: 块级作用域外部无法调用块级作用域内部定义的函数,如若必须调用,需像下面处理

    let f;
    {
        let a = 123;
        f = function () {
            return a;
        }
    }

    console.log(f());       //123
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值