美文网首页
块级作用域之LET CONST

块级作用域之LET CONST

作者: 刘越姐姐啊 | 来源:发表于2019-10-28 09:18 被阅读0次

    一、全局作用域

    用 var 在全局(函数外)声明的所有变量,都具有全局作用域,即: 网页中所有脚本和函数均可使用。

    (1)最外层函数和在最外层函数外面定义的变量拥有全局作用域,例如:

    var aName="哈哈";
    function doSomething(){
        var bName="嘿嘿";
        function innerSay(){
            alert(bName);
        }
        innerSay();
    }
    alert(aName); //哈哈
    alert(bName); //脚本错误
    doSomething(); //嘿嘿
    innerSay() //脚本错误
    

    (2)所有末定义直接赋值的变量自动声明为拥有全局作用域,例如:

    function doSomething(){
        var aName="哈哈";
        bName="嘿嘿";
        alert(aName);
    }
    doSomething(); //哈哈
    alert(bName); //嘿嘿
    alert(aName); //脚本错误
    

    二、局部作用域

    局部作用域一般只在固定的代码片段内可访问到,最常见的例如函数内部,例如下列代码中的bName和函数innerSay都只拥有局部作用域。在函数中用 var 声明的所有变量,都是函数的局部变量,具有局部作用域,即:变量只能在函数内部使用,函数外部是不行的

    function doSomething(){
        var bName="嘿嘿";
        function innerSay(){
            alert(bName);
        }
        innerSay();
    }
    alert(bName); //脚本错误
    innerSay(); //脚本错误
    

    三、存在的问题

    在ES5中,只有全局作用域和函数作用域。这会导致函数作用域覆盖了全局作用域;亦或者循环中的变量泄露为全局变量。

    (1)内层变量可能覆盖外层变量(变量提升)

     var tmp = new Date();
    
     function f(){
       console.log(tmp);
       var tmp = "hello";
     }
     
     f();//undefined
    
     var tmp = new Date();
    
     function f(){
       var tmp;
       console.log(tmp);
       tmp = "hello";
     }
     
     f();//undefined
    

    (2)用来计数的循环变量泄露为全局变量

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

    四、块级作用域

    ES6中新增了块级作用域,块级作用域由 { } 包括,if语句和for语句里面的{ }也属于块级作用域。ES6可以使用let关键字或者const关键字来实现块级作用域。let或const声明的变量只在let或const命令所在的代码块{}内有效,在{}之外不能访问。

    (1) 允许块级作用域任意嵌套,外层作用域无法读取内层作用域的变量

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

    (2) 内层作用域可以定义外层作用域的同名变量

    if(true){
        let a = 10;
        var b = 30;
        if(true){
            let a = 20;
            var b = 40;
            console.log(a);//20
            console.log(b);//40
        }
        console.log(a);//10
        console.log(b);//40
    }
    

    五、块级作用域之LET CONST

    (1)ES6 新增了let和const命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let和const命令所在的代码块内有效。

    if(1){
        var a = 100;
        let b = 10;
    }
    
    console.log(a); // 100
    console.log(b)  // 报错:b is not defined  ===> 找不到b这个变量
    
    for(let i =0; i<arr.length; i++){
    }
    console.log(i) //ReferenceError: i is not defined
    
        var arr = [];
        for (var i = 0; i < 10; i++) {
            arr[i]=function(){
                console.log(i);
            }
        }
        arr[2]();       //输出的是10    
    
        var arr = [];
        for (let i = 0; i < 10; i++) {
            arr[i]=function(){
                console.log(i);
            }
        }
        arr[2]();       //输出的是2
    

    (2)不存在变量提升,let和const命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。

    console.log(a); // undefined  ===>  a已声明还没赋值,默认得到undefined值
    var a = 100;
    
    console.log(b); // 报错:b is not defined  ===> 找不到b这个变量
    let b = 10;
    
    console.log(c); // 报错:c is not defined  ===> 找不到c这个变量
    const c = 10;
    

    (3)同一作用域下let和const不能声明同名变量,而var可以

    var a = 100;
    console.log(a); // 100
    
    var a = 10;
    console.log(a); // 10
    
    let a = 100;
    let a = 10;
    
    //  控制台报错:Identifier 'a' has already been declared  ===> 标识符a已经被声明了。
    

    (4)const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。但是这并不意味着不可变,如果声明的是复合类型数据,可以修改其属性

    const a = 100; //声明后不能再修改
    
    const list = [];
    list[0] = 10;
    console.log(list);  // [10]
    
    const obj = {a:100};
    obj.name = 'apple';
    obj.a = 10000;
    console.log(obj);  // {a:10000,name:'apple'}
    

    (5)暂时性死区(temporal dead zone):只要块级作用域内存在let和const 命令,它所声明的变量就“定”(binding)这个区域,不再受外部的影响。

    var tmp = 123;
    
    if (true) {
       tmp = 'abc'; // ReferenceError
       let tmp;
    }
    

    上面代码中,存在全局变量tmp,但是块级作用域内let又声明了一个局部变量tmp,导致后者绑定这个块级作用域,所以在let声明变量前,对tmp赋值会报错。

    ES6明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

    if (true) {
      // TDZ开始
      tmp = 'abc'; // ReferenceError
      console.log(tmp); // ReferenceError
    
      let tmp; // TDZ结束
      console.log(tmp); // undefined
    
      tmp = 123;
      console.log(tmp); // 123
    }
    

    (6)用let和const声明的变量不会挂载到顶层对象

    const a="aa";
    console.log(window.a);// undefined
    
    var b="bb";
    console.log(window.b);// bb
    
    window.a = 1;
    var a = 2 ;
    console.log(a);         // 2
    console.log(window.a);  // 2
    
    window.b = 1;
    let b = 2 ;
    console.log(b);         // 2
    console.log(window.b);  // 1
    

    六、VAR LET CONST的总结

    (1)var定义的变量,没有块的概念,可以跨块访问, 不能跨函数访问,不初始化出现undefined,不会报错。

    (2)let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问

    (3)const用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域里访问,而且不能修改,如果声明的是复合类型数据,可以修改其属性

    相关文章

      网友评论

          本文标题:块级作用域之LET CONST

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