前言:最近因爲公司項目太忙,好久沒有更新博客了,加上以前就一直說要發表一篇有關閉包的博客幫助小夥伴們好好的理解一些JavaScript中的難點。因此,今天趁着國慶假期前趕忙寫了去,寫完國慶好好出去浪個夠。
首先,必需要提的就是閉包它絕對算的上是JavaScript中的一大難點,固然也是一大重點。N多高級程序都須要或者必須用到閉包才能得以實現。參考了N篇很牛叉的對於閉包理解的文章,接下來我將陳述一下鄙人本身對於閉包的理解,但願能夠幫助小夥伴們通俗切入閉包這個點。javascript
一、變量做用域
理解閉包很重要的一點就是須要先理解JavaScript特殊的變量做用域。
而變量做用域無非兩種形式,全局變量和局部變量。而在JavaScript中,全部的函數它均可以在其內部訪問到全局變量。java
var n = 123; function test1(){ alert(n); } test1(); //123
而在函數外部也沒法讀取函數內的局部變量。閉包
function test1(){ var n=123; } test1(); alert(n); // Uncaught ReferenceError: n is not defined
固然在定義變量的時候,必定要記住加上var關鍵字,否則,JavaScript會默認你定義了一個全局變量。函數
function test1(){ n=123; } test1(); alert(n); // 123
二、函數外部訪問局部變量
不少時候咱們須要在一個函數中去訪問另一個函數內部的局部變量,但是上面又說了一個函數內部的局部變量是不容許被其餘函數訪問的。怎麼辦呢?
那咱們就須要在函數內部在定義一個函數,這樣就能夠在其內部函數中訪問到它內部的局部變量了。上代碼理解。性能
function test1(){ // 函數test2就被包括在函數test1內部,這時test1內部的全部局部變量,對test2都是可見的 var n=123; function test2(){ // test2內部的局部變量則不能被test1訪問 // 這就是Javascript語言特有的"鏈式做用域"結構(chain scope),子對象會一級一級地向上尋找全部父對象的變量。因此,父對象的全部變量,對子對象都是可見的,反之則不成立。 var n1 = 321; alert(n); } //alert(n1); // error return test2; } var result=test1(); result(); // 123
而上面代碼中的test2就是一個閉包,它是一種可以讀取其餘函數內部變量的函數,或者直接理解爲定義在一個函數內部的函數。this
三、閉包的用途
閉包能夠用在不少地方。但它最大的用處有兩點。第一點是以上提到的,訪問其餘函數內部的局部變量。還有一個很重要的用途則是讓這些變量始終保存在內存中。很少解釋,直接看代碼理解code
function test1(){ /** * test1是test2的父函數,而test2被賦給了一個全局變量result,這致使test2始終在內存中 * 而test2的存在依賴於test1,所以test1也始終在內存中 * 這樣test1中的局部變量就不會在調用結束後,被垃圾回收機制回收。 */ var n=123; // nAdd前面沒有var關鍵字,它是一個全局變量。nAdd的值是一個匿名函數,而這個匿名函數自己也是一個閉包 // 它至關於一個setter,能夠在函數外部對函數內部的局部變量進行操做。 nAdd = function(){ n+=1 } function test2(){ alert(n); } return test2; } var result=test1(); result(); // 123 nAdd(); result(); // 124
四、閉包使用中需注意的問題對象
1)因爲閉包會使得函數中的變量都被保存在內存中,內存消耗很大,因此不能濫用閉包,不然會形成網頁的性能問題,在IE中可能致使內存泄露。解決方法是,在退出函數以前,將不使用的局部變量所有刪除。ip
2)閉包會在父函數外部,改變父函數內部變量的值。因此,若是你把父函數看成對象使用,把閉包看成它的公用方法,把內部變量看成它的私有屬性,這時必定要當心,不要隨便改變父函數內部變量的值。內存
五、練習思考題
當你能夠理解如下兩段代碼運行結果時,那麼恭喜你,你已經理解了閉包的運行機制了。
//代碼一 var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name; }; } }; alert(object.getNameFunc()());
//代碼二 var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ var that = this; return function(){ return that.name; }; } }; alert(object.getNameFunc()());
好了,文章最後。仍是那句話,若是覺着能夠幫助到小夥伴的話,求點個贊哦。若覺着哪裏有說錯或者寫錯的地方,還請小夥伴們輕噴,可是歡迎小夥伴隨時指正博客中的錯誤而後你們一塊兒交流探討!(*^__^*)