01.JS塊級做用域與let

1.塊級做用域
   什麼是:
         在一個代碼塊(括在一對花括號中的一組語句)中定義的所需變量(與let配合使用)並在代碼塊的外部是不可見的。
   爲何:
         在ES6以前,函數只能在全局做用域和函數做用域中聲明,不能在塊級做用域中聲明,形成諸多問題:
              1.內層變量會覆蓋外層變量
              2.用來計數的循環變量泄漏變成全局變量
   什麼時候:
         須要強化對變量生命週期的控制,避免全局污染出現錯誤
   優勢:
         1.阻止變量泄漏變爲全局變量,形成全局污染
         2.阻止變量提高覆蓋
         3.內層做用域能夠定義與外層做用域相同的變量名,但變量是獨立的。
         4.容許任意嵌套,外層做用域沒法讀取內層做用域的變量
   塊級做用域:
         {},if{},else{},while{},for{},swicth{}…函數

    //塊級做用域{},與let配合使用
    {
      //大括號之間就是塊級做用域
      var num=1;//仍是全局變量,能夠被外部訪問
      let num=1;//局部變量,不能夠被外部訪問,塊級做用域必須用let聲明
    }
    console.log(num);//此時num已經不能夠被訪問,說明塊級做用域生效

    //內層做用域能夠定義與外層做用域相同的變量名,容許任意嵌套
    //但變量與變量之間是沒有關係的,都是獨立的個體。
    {
      let aa=1;
      console.log(aa);//1
      {
        let aa=11;
        console.log(aa);//11
        {
          let aa=111;
          console.log(aa);//111
        }
      }
    }
    console.log(aa);//此時是不能被訪問的,防止aa泄露爲全局變量

    //防止變量提高形成覆蓋
    //雖然都是f,可是配合了let使用,{}內部變成了一個小個體,不會影響其餘的f
      var f=17;
      {
        let f=28;
        console.log(f);
      }
      console.log(f);

    //for塊級做用域
    //計算1-100之間全部的整數的和,使用var聲明
    for (var i=1,sum=0;i<=100;i++){
      sum+=i;
    }
    console.log(sum);//5050,能夠訪問
    console.log(i);//101,能夠訪問

    //使用let聲明變量
    for (let i=1,sum=0;i<=100;i++){
      sum+=i;
    }
    console.log(i);//此時i是不能被訪問的。
    console.log(sum);//此時sum是不能被訪問的。
    //根據需求得知,最後須要訪問的是sum,i須要釋放
    //因此把sum單獨放在外面,sum就能夠被訪問,而i會被釋放
    var sum=0;
    for (let i=1;i<=100;i++){
      sum+=i;
    }
    console.log(sum);

2.let聲明
   什麼是:
         專門代替var來聲明變量用的
   爲何:
         var的問題:
             1.聲明提早
             2.沒有塊級做用域
             3.形成全局污染
   什麼時候:
         只要聲明變量都用let
   優勢:
         1.阻止了聲明提早
         2.添加了塊級做用域
         3.成爲局部變量,不會形成全局污染
   原理:
         let其實就是一個匿名函數自調用!
         且let爲了雙保險,其實在底層悄悄給變量改了名字,在變量前增長了_
   let的小脾氣:
         1.在相同做用域/塊內:禁止同時let兩個同名的變量
         2.在let 變量 以前到當前做用域的頂部之間,不容許提早使用變量
         3.不能夠在函數內部重複聲明參數spa

    //1.簡單瞭解let聲明的變量
    let a=2;
    console.log(a);
    let a=3;
    console.log(a);//報錯,a不能重複聲明並賦值

    //var聲明的變量能夠重複聲明並從新賦值
    var b=2;
    console.log(b);//2
    var b=3;
    console.log(b);//3

    //在塊級做用域內{}
    {
      var c=2;
      let c=4;//在同一塊級做用域內不容許重複聲明變量
      let d=3;
      console.log(d);//只能在當前{}塊級做用域內訪問
    }
    console.log(c);//能夠被外部訪問的是var聲明的c
    console.log(d);//不能夠被外部訪問

    //let不容許先調用,後聲明
    {
      console.log(aaa);
      let aaa=5;//報錯Cannot access 'aaa' before initialization
    }

         把let放入實例中理解日誌

        //let應用
        //累加每一個任務函數的時間
        var t=0;
        function task1(){
            console.log(`任務1耗時3s`);
            t+=0.3;
        }
        function task2(){
            console.log(`任務二耗時8s`);
            t+=0.8;
        }
        task1();
        task2();
        console.log(`共耗時${t}s`)
         以上是一個能夠正常執行的代碼,而且是正確的程序
         若是在task2內添加其餘的功能,例如捕捉錯誤
        //累加每一個任務函數的時間
        var t=0;//聲明變量t準備累加每一個任務函數的時間
        function task1(){
            console.log(`任務1耗時3s`);
            t+=3;
        }
        function task2(){
            console.log(`任務二耗時8s`);
            t+=8;
            //模擬出錯的變量,此段代碼是不執行的
            var err=false;
            //若是出錯
            if(err==true){
                //就得到出錯時間
                var t=new Date();
                //並輸出出錯提示日誌
                console.log(`出錯啦,at:${t.toLocaleDateString()}`);
            };
        }
        task1();
        task2();
        console.log(`共耗時${t}s`)
         代碼正常執行,if內代碼是不執行的,可是結果倒是錯誤的,少了8s,那麼爲何少了8s呢?
         原來是由於var聲明的變量是全局變量,而if{}不是做用域,沒有實體牆,攔不住var,
         因此var聲明的變量會提高到當前做用域task2的最前面。
        //累加每一個任務函數的時間
        var t=0;//全局t
        function task1(){
            console.log(`任務1耗時3s`);
            t+=3;
        }
        function task2(){
            //var t;//undefined,var聲明的t提早到該做用域最前面,而且沒有賦值
            //若是task2()中已經有了局部變量t,就不會用全局的t了,只有在局部沒有的t的時候纔會調用全局的t
            console.log(`任務二耗時8s`);
            //這個8s沒有加到全局t,而是加在局部t上,當函數調用後,局部的t就被釋放了
            t+=8;//task2中的局部變量t,加在這裏
            var err=false;//模擬出錯的變量
            //若是出錯
            if(err==true){//if else for while do whlie 等程序結構的{}不是做用域,不是實體牆,攔不住var
                //就得到出錯時間
                var t=new Date();
                //並輸出出錯提示日誌
                console.log(`出錯啦,at:${t.toLocaleDateString()}`);
            };
        }
        task1();
        task2();
        console.log(`共耗時${t}s`)//此處輸出的是全局的t,因此沒有那8s,
         那麼鑑於這種明明沒有執行的代碼,卻破壞了本來正確的代碼,
         這就是沒有塊級做用域帶來的危害,此時就須要使用let聲明變量了,
         由於let會阻止聲明提早,並會添加塊級做用域
       //累加每一個任務函數的時間
        var t=0;//全局t
        function task1(){
            console.log(`任務1耗時3s`);
            t+=3;
        }
        function task2(){
            console.log(`任務二耗時8s`);
            t+=8;//這個t仍是會加到全局的t上,沒有被影響
            //模擬出錯的變量
            //var err=false;//代碼不執行
            var err=true;//代碼執行
            //若是出錯
            if(err==true){//let將if{}也變成了一級做用域,這個做用域是有實體牆的,是能夠攔住let聲明的變量的                //就得到出錯時間
                //let阻止了局部的t被聲明提早
                let t=new Date();//此時的t是在這個if塊級做用域的函數內,不會存在提高
                //並輸出出錯提示日誌
                console.log(`出錯啦,at:${t.toLocaleDateString()}`);//因此此時輸出的t也是if內的t
            };
        }
        task1();
        task2();
        console.log(`共耗時${t}s`)//打印全局t
         let的原理,添加匿名函數自調用,並改變名字
        //累加每一個任務函數的時間
        var t=0;//全局t
        function task1(){
            console.log(`任務1耗時3s`);
            t+=3;
        }
        function task2(){
            console.log(`任務二耗時8s`);
            t+=8;//這個t仍是會加到全局的t上,沒有被影響
            //var err=false;
            var err=true;//模擬出錯的變量
            //若是出錯
            if(err==true){//let將if{}也變成了一級做用域,這個做用域是有實體牆的,是能夠攔住let聲明的變量的
                //(function(){//let自動添加的
                //就得到出錯時間
                //let阻止了局部的t被聲明提早
                let t=new Date();//let悄悄改變了名字,變成了_t,此時的t是在這個if塊級做用域的函數內,不會存在提高到
                //並輸出出錯提示日誌
                console.log(`出錯啦,at:${t.toLocaleDateString()}`);//_t,因此此時輸出的t也是if內的t
                //})();//let自動加的
            };
        }
        task1();
        task2();
        console.log(`共耗時${t}s`)//打印全局t    

         單詞:
               declare——聲明
               access——訪問
               initialization——初始化——>第一次聲明+賦值=初始化code

相關文章
相關標籤/搜索