閉包的「官方」解釋是:所謂「閉包」,指的是一個擁有許多變量和綁定了這些變量的環境的表達式(一般是一個函數),於是這些變量也是該表達式的一部分。這種文字上的定義確實很差理解,也不知道它說的函數是哪一個函數,但若是咱們記住了閉包的兩種狀況,和閉包的做用,或許對閉包會有更好的理解,而沒必要在乎於它的文字定義。閉包
閉包的做用:函數
①爲了突破做用域(對於做用域上篇有介紹),使得咱們好像在函數外部也能訪問在函數內部定義的局部變量,注意這裏用了「好像」一詞,由於閉包並不能讓咱們真正作到在函數外部直接使用函數內部定義的局部變量,可是能夠經過某些方法間接使用,而爲何要在函數內部定義變量呢,而不直接在函數外部定義,是爲了造成模塊,防止變量污染。code
function fn1(){ var a=2; function fn2(){ console.log(a); } return fn2; } var fn3=fn1(); fn3(); // 2
上面這段代碼,使得函數fn2在函數fn1外部獲得了執行,是由於在fn1內部有個return,將fn2返回了。內存
var foo=(function CoolModule(){ var something = "cool"; var another = [1,2,3]; function doSomething(){ console.log(something) } function doAnother(){ console.log(another.join("!")) } return{ doSomething:doSomething, doAnother:doAnother } })(); foo.doSomething(); // cool foo.doAnother(); // 1!2!3
這段代碼也同樣,使得局部變量 doSomething和doAnother這兩個函數在外部都獲得了執行。這個函數造成模塊,只有一個foo變量暴露在全局做用域中。作用域
②爲了使得變量一直保存在內存中,不被垃圾回收機制回收。看下面的代碼:io
function outerFun() { var a=0; function innerFun() { a++; console.log(a); } return innerFun; } var obj=outerFun(); obj(); // 1 obj(); // 2 var obj2=outerFun(); obj2(); // 1 obj2(); // 2
以上的閉包應用狀況中都有一個return,將函數做爲返回值,這就是閉包的一種應用狀況,還有一種就是將變量做爲參數傳遞。console
for(var i=1;i<=5;i++){ setTimeout(function timer(){ console.log(i) },i*1000) }
可能你會認爲這段代碼的輸出結果爲1-5,可是程序的結果跟咱們的預期老是不同,正確結果爲輸出五次6,這是由於延遲函數的回調會在循環結束時才執行,因此那時i已經等於6。能夠將代碼改進以下,結果爲1-5。function
for(var i=1;i<=5;i++){ (function (j){ setTimeout(function timer(){ console.log(j) },j*1000) })(i) }
這就是閉包的做用和應用狀況,至於閉包的第二種用法(本文最後一個代碼)與前面所介紹的閉包做用有什麼關係我自個也還不是很清楚,能夠一塊兒討論。變量