# 1、前言javascript
這個週末,注意力都在學習基礎Js知識上面,恰好看到了閉包這個神聖的東西,因此打算把這兩天學到的總結下來,算是鞏固本身所學。也可能有些不正確的地方,也請你們看到了,麻煩在評論下提醒一下,算是互相學習了。html
百度百科定義:閉包就是可以讀取其餘函數內部變量的函數。
在解釋以前,得先講講做用域。先來看下面這個示例:java
var a = 1; function f(){ var b = 2; console.log(a) // 1 } console.log(b) // undefined
示例中包含了兩種做用域,一種是屬於全局的全局做用域,另外一種是屬於函數f
的局部做用域。因爲Javascript
這種鏈式做用域(父做用域是能夠被其子做用域訪問的,而子做用域卻不能被父做用域訪問)的機制,使得示例最後一行輸出了undefined
閉包
今後能夠看出,沒法從父做用域中訪問子做用域。而咱們再來看閉包的定義:閉包就是可以讀取其餘函數內部變量的函數。也就是閉包可讓咱們從父做用域中訪問到子做用域,具體怎麼實現的呢?來看這個經典的例子:異步
function foo(){ var a = 2; function bar(){ console.log(a); } return bar; } var baz = foo(); baz(); // 2 -> 這就是閉包的效果
這個示例中,閉包就是函數bar
。能夠看到,咱們經過在函數foo
內部定義其子函數bar
,並將其做爲foo
返回值,由於bar
函數做用域能夠訪問foo
的做用域,因此實現了從全局做用域訪問foo
函數做用域的效果。函數
其實,平時你所寫的代碼中,早就用到了閉包,只是你還沒發現而已。性能
本質上,不管什麼時候何地,若是將函數看成值傳遞到其餘地方使用(非函數所在做用域),你就已經使用了閉包。例如上面示例說的函數bar
,咱們將他傳遞到了全局做用域下,經過這種方式訪問到本該不能訪問的變量a
。學習
在定時器、事件監聽器、Ajax請求、任何其餘異步(或同步)任務中,只要使用了回調函數,實際上就是在使用閉包!code
閉包會讓他所在做用域中的變量始終保存在內存中,而不會被垃圾回收機制回收。htm
function foo(p){ function bar(){ console.log(++p); } return bar; } var baz = foo(1); baz(); // 2 baz(); // 3 baz(); // 4 var bazz = foo(2); bazz(); // 3 bazz(); // 4 bazz(); // 5 baz(); // 5
看到了沒,閉包的使用,函數調用以後,讓其外層函數的內部變量(foo
函數內的變量)始終保存在了內存中,而不會被回收。
值得注意的是,每次調用一次foo
,都會生成一個新的閉包,都會在內存中保存下其外層函數的內部變量。所以要注意閉包的使用,不然會致使性能問題。
閉包的做用:
參考:
附:你不知道的Javascript系列電子書網盤連接, 密碼:i8jf