js塊級作用域和let,const,var區別


1. 塊作用域{ }

JS中作用域有:全局作用域、函數作用域。沒有塊作用域的概念。ECMAScript 6(簡稱ES6)中新增了塊級作用域。
塊作用域由 { } 包括,if語句和for語句里面的{ }也屬於塊作用域。

我們都知道在javascript里是沒有塊級作用域的,而ES6添加了塊級作用域,塊級作用域能帶來什么好處呢?為什么會添加這個功能呢?那就得了解ES5沒有塊級作用域時出現了哪些問題。

       ES5在沒有塊級作用域的情況下出現的問題:

       一。在if或者for循環中聲明的變量會泄露成全局變量

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

      二。內層變量可能會覆蓋外層變量

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

     不管最后是否執行if語句,都會輸出undefined,因為temp會提升到函數頂部,因此覆蓋了外部的變量temp。

     上一篇介紹的let和const命令,它們所聲明的變量只在所在的代碼塊內有效,即為js添加了塊級作用域。

           【1】允許塊級作用域任意嵌套;

{{{let tmp = "hello world"}}}

           【2】外層作用域無法讀取內層作用域的變量;

{{{
   {let tmp = "hello world";}
   console.log(tmp);  //error
}}}

           【3】內層作用域可以定義外層作用域的同名變量

{{{
   let tmp = "hello world";
   {let tmp = "hello world";}
}}}

           【4】函數本身的作用域在其所在的塊級作用域之內。

復制代碼
function f(){
    console.log("outside");
}
(function(){
    if(false){
        function f(){
            console.log("inside");
        }
    }
   f();
}());
復制代碼

這段代碼如果是在ES5中運行,那么會輸出inside,因為在ES5中,函數會提升到作用域的頂部,如果是在ES6中運行,則會輸出outside,因為在ES6中函數無法提升,所以訪問到的f()是外層的f()。

         【5】在ES5中,因為沒有塊級作用域,獲得廣泛運用的是立即執行函數。現在ES6增加了塊級作用域,那么立即執行函數就不再必要了。ES6以前變量的作用域是函數范圍,有時在函數內局部需要一些臨時變量,因為沒有塊級作用域,所以就會將局部代碼封裝到IIEF(立即執行函數)中,這樣達到了想要的效果又不引入多余的臨時變量。而塊作用域引入后,IIEF當然就不必要了!臨時變量被封裝在IIFE中,就不會污染上層函數;而有塊級作用域,就不用封裝成IIEF,直接放到一個塊級中就好。更簡單的說法是,立即執行匿名函數的目的是建立一個塊級作用域,那么現在已經有了真正的塊級作用域,所以立即執行匿名函數就不需要了。

//立即執行函數
(function(){
    var temp = "hello world";
}());
//塊級作用域
{
   var temp = "hello world";
}

2. var、let、const的區別

  1. var定義的變量,沒有塊的概念,可以跨塊訪問, 不能跨函數訪問,有變量提升。
  2. let定義的變量,只能在塊作用域里訪問,不能跨塊訪問,也不能跨函數訪問,無變量提升,不可以重復聲明。
  3. const用來定義常量,使用時必須初始化(即必須賦值),只能在塊作用域里訪問,而且不能修改,無變量提升,不可以重復聲明。注意:const常量,指的是常量對應的內存地址不得改變,而不是對應的值不得改變,所有把應用類型的數據設置為常量,其內部的值是可以改變的,例如:const a={}; a.b=13;//不會報錯 const arr=[]; arr.push(123);//不會報錯
  4. let 聲明的變量只在塊級作用域內有效

    'use strict';
    function func(args){
        if(true){
            let i = 6;
            console.log('inside: ' + i);  //不報錯
        }
        console.log('outside: ' + i);  // 報錯 "i is not defined"
    };
    func();

    不存在變量提升,而是“綁定”在暫時性死區

    // 不存在變量提升
    'use strict';
    function func(){
        console.log(i);
        let i;
    };
    func(); // 報錯

    在let聲明變量前,使用該變量,它是會報錯的,而不是像var那樣會‘變量提升’。
    其實說let沒有‘變量提升’的特性,不太對。或者說它提升了,但是ES6規定了在let聲明變量前不能使用該變量。

    'use strict';
    var test = 1;
    function func(){
        console.log(test);
        let test = 2;
    };
    func();  // 報錯

    如果let聲明的變量沒有變量提升,應該打印’1’(func函數外的test);而它卻報錯,說明它是提升了的,只是規定了不能在其聲明之前使用而已。我們稱這特性叫“暫時性死區(temporal dead zone)”。且這一特性,僅對遵循‘塊級作用域’的命令有效(let、const)。

    let使用經典案例:let命令代替閉包功能
    閉包實現:

    var arr = [];
    for(var i = 0; i < 2; i++){
        arr[i] = (function(i){
            return function(){
                console.log(i);
            };
        }(i));
    };
    arr[1]();
    let 實現:
    
    'use strict';
    var arr = [];
    for(let i = 0; i < 2; i++){
        arr[i] = function(){
            console.log(i);
        };
    };
    arr[1]();

    剩下 const 命令了!
    const 與 let 的使用規范一樣,與之不同的是:
    const 聲明的是一個常量,且這個常量必須賦值,否則會報錯。

    'use strict';
    function func(){
        const PI;
        PI = 3.14;
        console.log(PI);
    };
    func(); // 報錯“Missing initializer in const declaration”


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM