什麼是做用域?
在當前運行環境下,能夠訪問的變量或函數的範圍。
做用域分爲詞法做用域和動態做用域。
詞法做用域是在js代碼編譯階段就肯定下來的; 對應的,with
和eval
語句會產生動態做用域。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中則可能致使內存泄露