理解閉包概念:javascript
a、閉包是指有權限訪問另外一個函數做用域的變量的函數,建立閉包的常見方式就是在一個函數內部建立另外一個函數,也就是建立一個內部函數,建立一個閉包環境,讓返回的這個內部函數保存要引用的變量,以便在後續執行時能夠保持對這個變量的引用。css
b、只要存在調用內部函數的可能,JavaScript就須要保留被引用的函數。並且JavaScript運行時須要跟蹤引用這個內部函數的全部變量,直到最後一個變量廢棄,JavaScript的垃圾收集器才能釋放相應的內存空間。html
c、Javascript語言特有的"鏈式做用域"結構(chain scope),子對象會一級一級地向上尋找全部父對象的變量。java
d、若是一個內部函數被調用且引用了它的外部變量那麼它就是一個閉包。安全
相信你看了上面的這段話可能還不理解什麼是閉包,那麼我就舉一個閉包的經典例子來幫助你理解閉包的概念吧。閉包
請看下面這段代碼: 函數
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>閉包</title> </head> <body> <script type="text/javascript"> function out() { var i = 0; function inner() { alert(++i); } return inner; } var ref= out(); ref(); </script> </body> </html>
結果:性能
上面的代碼有兩個特色:
一、建立兩個函數out,inner,函數inner嵌套在函數out內部,也能夠說是函數inner是函數out的內部函數;
二、調用函數out返回內部函數inner。
這樣在執行完var ref=out()後,變量ref其實是指向了函數inner,也能夠說是引用了函數inner,再執行ref()後就會看到上圖彈出一個窗口顯示i的值第一次爲1。網站
這段代碼其實就建立了一個閉包,爲何?由於函數out外的變量ref引用了函數out內部的函數inner,也就是說:this
當函數out的內部函數inner被函數out外的一個變量ref引用的時候,就建立了一個閉包。
可能你仍是不理解閉包這個概念,由於你不知道閉包有什麼用,那麼先理解一下閉包的做用吧。
解釋:以上面的的例子爲例,函數out中i只有函數innder才能訪問,而沒法經過其餘途徑訪問到,所以保護了i的安全性。
在上面的示例中增長了一次函數ref()的調用,執行的結果以下:
解釋:當函數out執行完而且最終退出時,它的局部變量會被Javascript的垃圾回收機制回收所佔用的資源,也就是局部變量被銷燬,可是由於建立了閉包環境,那麼內部函數inner就會暫時保存外部函數的局部變量上下文環境。不會被垃圾回收機制回收。因此函數out中的i被複制一份暫時保存下來,這樣每次執行ref(),i都是自加1後alert輸出i的值。這只是我對閉包做用的簡單初淺理解,不專業也不嚴謹,但大概意思就是這樣,理解閉包須要按部就班的過程。
相信你看了閉包的做用,對理解什麼是閉包是否更明白一些,若是仍是很疑惑,那麼我就再舉幾個閉包的經典例子來幫助你理解閉包的概念吧。
問題:假如咱們有以下需求請在頁面中放10個div,每一個div寫上對應的數字,當點擊每個div時顯示索引號,如第1個div顯示0,第10個div顯示9。
可能你會這樣作:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>閉包</title> <style type="text/css"> div { width: 50px; height: 50px; background: lightcoral; float: left; margin: 20px; font: 15px/50px "microsoft yahei"; text-align: center; } </style> </head> <body> <div>div-1</div> <div>div-2</div> <div>div-3</div> <div>div-4</div> <div>div-5</div> <div>div-6</div> <div>div-7</div> <div>div-8</div> <div>dvi-9</div> <div>div-10</div> <script type="text/javascript"> var divs=document.getElementsByTagName("div"); for (var i=0;i<divs.length;i++) { divs[i].onclick=function(){ alert(i); } } </script> </body> </html>
結果:
從上面的結果你會發現,無論你點擊了哪一個div,彈出的框div索引老是10,這可能會讓你很意外,會產生疑惑,爲何會出現這樣的結果呢?
解釋:由於點擊事件的函數內部使用外部的變量i一直在變化,當咱們指定click事件時並無保存i的副本,這樣作也是爲了提升性能,但達不到咱們的目的,咱們要讓他執行的上下文保存i的副本,這種機制就是閉包。
使用閉包能夠解決此問題,代碼作了以下修改:
<script type="text/javascript"> var div=document.getElementsByTagName("div"); for (var i = 0; i < div.length; i++) { div[i].onclick=function(n){
return function(){ alert(n);//產生閉包,引用外部變量。 } }(i); } </script>
結果:
從上面的結果你會發現,使用閉包後,就達到你預期的結果了。
解釋:n是外部函數的值,可是內部函數須要使用這個值,由於產生閉包執行環境,因此返回函數前的n被臨時駐留在內存中給點擊事件使用,簡單說就是函數的執行上下文被保存起來,i生成了多個副本。
示例代碼:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <script type="text/javascript"> function out() { var i = 10; return function inner() { i++; alert(i);//引用了外部變量,建立了閉包環境 }; } //此處爲函數調用,第一個括符爲調用out方法,第二個括符爲調用返回的inner方法。 out()(); </script> </body> </html>
運行 結果:
示例代碼:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>閉包</title> </head> <body> <script type="text/javascript"> var name = "this is Window"; var obj = { name: "My Object", getNameFunc: function() { alert(this.name);//輸出My Object return function() { return this.name; }; } }; var funn=obj.getNameFunc(); alert(funn());//輸出this is Window </script> </body> </html>
運行結果:
解釋:funn是屬於方法調用,因此this綁定到了obj對象,天然this.name就是"My Object",可是閉包函數沒法訪問這個this,它只能訪問到全局的this,因此this.name就是「this is Window」.
總結:相信經過以上是幾個閉包示例,你對閉包也有必定的理解了吧。限於本人才疏學淺,對閉包的理解也並非很透徹,只是理解了一些表面,會使用而已。若你想理解的更深刻推薦你去看stackoverflow這個網站上對閉包的解釋:http://stackoverflow.com/questions/111102/how-do-javascript-closures-work