Javascript中的做用域與閉包

什麼是做用域?
在當前運行環境下,能夠訪問的變量或函數的範圍。
做用域分爲詞法做用域動態做用域
詞法做用域是在js代碼編譯階段就肯定下來的; 對應的,witheval語句會產生動態做用域。javascript

會產生新的做用域的狀況:java

  • 函數
  • {}(ES6)
  • eval

舉個例子說明做用域閉包

var a = 'hello';
function f1(){
    var a = 1;
    console.log(a);
}
f1();  // 1
console.log(a); // hello

能夠看到f1中的變量a只能在f1中有效,f1外部訪問不到裏面的a;因此在f1中的a,其做用域就只限定在f1中。函數

再來個新概念:做用域鏈性能

var a = 'hello';
function f1(){
    console.log(a);// ps: f1中並未聲明a
}
f1(); // hello

之因此輸出hello, 是由於在f1中並未找到a的定義,此時程序並不會急於拋異常,而是會向調用f1的上一層尋找a的定義。若是沒有,會繼續再往上一層的上一層尋找,直到最頂層。
這樣就造成了一個鏈式的做用域。code

什麼是閉包?對象

一般來說,函數能夠訪問函數外面的變量;可是在函數外部,訪問不到在函數裏面定義的變量。ip

function f1(){
    var a = 1;
}
console.log(a);  // Uncaught ReferenceError: a is not defined

那麼有沒有可能訪問到f1中的a呢?固然是有的, 看例子:內存

function f1(){
    var a = 1;
    function f2(){
        return a;
    }
    return f2;
}
var getA = f1();
console.log(getA()); // 1

咱們在f1中,添加了一個函數f2(實際上f2就能夠看作一個閉包)。
通常狀況下,當函數執行完畢時,裏面的變量會被自動銷燬。可是由於咱們把f2賦值給了外部的getA,因此f2不會被內存釋放,同理f2中使用的a在f2的做用域中,也不會被釋放,因此這個時候就能夠訪問到a。
而getA可以訪問到a,這個在js的編譯階段就已經定型了(詞法做用域)。作用域

官方」的解釋是:閉包是一個擁有許多變量和綁定了這些變量的環境的表達式(一般是一個函數),於是這些變量也是該表達式的一部分。
相信不多有人能直接看懂這句話,由於他描述的太學術。其實這句話通俗的來講就是:閉包就是可以讀取其餘函數內部變量的函數。

閉包的特色閉包能夠在函數外部改變函數中的變量的值,若是你把函數做爲對象、閉包做爲方法、局部變量做爲私有屬性使用,則會改變該變量的值;閉包還會把函數中的變量的值存儲於內存中,對內存消耗很大,因此濫用閉包的結果就是影響網頁性能,IE中則可能致使內存泄露

相關文章
相關標籤/搜索