1. 程式人生 > >塊級作用域與函式作用域

塊級作用域與函式作用域

函式作用域:變數在定義的環境中以及巢狀的子函式中處處可見;
塊級作用域:變數在離開定義的塊級程式碼後立即被回收。

函式作用域

在ES6之前,js的作用域只有兩種:函式作用域和全域性作用域。使用var宣告的變數,都存在變數提升的過程。

    console.log(a); //undefined
    console.log(c); //undefined
    console.log(d); //function d() {}
    console.log(b); //報錯,b is not defined
    
    var a = 0;
    let b = 1;
    var c = function
() { }; function d() { }

由此可見使用let宣告的變數不會提升,函式宣告會完全提升。上面的程式碼等價於:

    var a;
    var c;
    function d() {}
    
    console.log(a);
    console.log(c);
    console.log(d);
    console.log(b);
    
    a = 0;
    let b = 1;
    c = function () {

    };
  

塊級作用域

ES6中定義了塊級作用域,使用let宣告的變數只能在塊級作用域裡訪問,有“暫時性死區”的特性(也就是說宣告前不可用)。

'use strict';
var test = 1;
function func(){
    //列印test的值
    console.log(test); //報錯, test is not defined.
    let test = 2;
};
func();

函式會從自身的活動物件開始,一層層向上尋找自己所需的變數,該函式在尋找test時發現,自己的作用域裡聲明瞭let,它就不會再往上找,而let在宣告之前是不可用的,所以就會報錯。

自己的理解

雖然《js高程》裡說,ES6之前,js沒有塊級作用域。但我認為with語句和try-catch語句有類似於塊級作用域的地方。

    var
l = { x: 0, y: 1 }; function f() { with(l) { console.log(x); //0 var a = 1; } cosnole.log(a); //1 console.log(x); //報錯,x is not defined. } f();

函式f利用with語句擴充套件了自己的作用域鏈,相當於with語句開始執行時,引數l中所包含的所有變數都被臨時加入到該函式的活動物件中,等到語句執行結束,它們就會被移除。它們只在with語句塊中有效。還有一點就是,with語句中宣告的變數a,使用var宣告的變數會自動被新增到離它最近的環境中,離a最近的環境就是函式的區域性環境,所以a就會被新增到函式的活動物件中,即使在with語句之外也能被訪問。