淺談javascript做用域

理解做用域

做用域負責收集並維護由全部聲明的變量組成的集合,等待引擎的查找。閉包

var a = 2;
console.log(a);  // 2
console.log(b);  // ReferenceError: b is not defined
  1. var a = 2 能夠分解爲var a; a = 2。當遇到var a時,編譯器會詢問做用域是否存在變量a。若是存在,則忽略該聲明,不然會在當前做用域的集合中聲明一個新的變量a
  2. 遇到a = 2時,引擎會詢問當前做用域是否存在變量,若是未找到,則會繼續在上級做用域查找。若是最終找到就會將2賦值給變量a
  3. console.log(a)時,引擎會去做用域中查找 a,找到把結果返回,輸出2, console.log(b)時,引擎未在做用域查找到b,拋出異常。

LHS和RHS查詢

能夠看出'L'和'R'分別表明左側和右側,即賦值的左側和右側。賦值不僅是=的賦值,函數參數的傳遞也是一種賦值操做。函數

var a = 2;  // LHS查詢,a出如今賦值左側
console.log(a);  // RHS查詢, a出如今賦值右側,將變量a賦值給參數

查詢失敗會出現什麼狀況
對於LHS查詢a = 2 若a未找到,在非嚴格模式下並不會報錯,而變量 a 會被自動建立。而對於 RHS 來講,直接使用未聲明的變量就會報 ReferenceError。code

console.log(b);  // ReferenceError: b is not defined

詞法做用域

做用域主要有兩種工做模型:詞法做用域和動態做用域。
詞法做用域就是定義在詞法階段的做用域。換句話說,詞法做用域是由你寫代碼時變量和塊做用域寫在哪決定的。ip

function foo(a) {
    var b = a * 2;
    function bar(a) {
        console.log(a, b, c);
    }
    bar(b*3);
}
foo(2);

在這個例子有三個逐級嵌套的做用域。作用域

  1. 全局做用域,包含一個標識符:foo
  2. foo所建立的做用域,包含三個標識符:a, bar, b
  3. bar所建立的做用域,包含一個標識符:c

函數做用域

函數做用域是指屬於這個函數的變量均可以在整個函數範圍內使用和複用。編譯器

function fn() {
    var a = 2;
    console.log(a);  // 2
}

console.log(a); // ReferenceError: a is not defined

從中能夠看出,函數外部將沒法訪問函數內部的變量。it

塊做用域

ES6引入letconst將變量綁定到所在塊做用域(一般是{...}內部)io

{
    let a = 2;
    console.log(a);  // 2
}
console.log(a);  // ReferenceError: a is not defined

letconst外,withtry/catchcatch分句會建立一個塊做用域。console

小結

函數是Javascript中最多見的做用域單元。但函數不是惟一的做用域單元。塊做用域屬於某個代碼塊(一般指{...}內部)。
接下來會講解提高和閉包兩個概念。編譯

相關文章
相關標籤/搜索