標籤:函數 bsp glob http logs 屌絲 語言 推薦 記憶體
序:閉包這個玩意啊~在很多沒有代碼塊的語言中都會出現,已經成為大多程式員入門的一道坎,閉包讓很多程式員覺得晦澀(事實上百度一下這個名詞,真的說的很晦澀啊親==|||),本座第一次知道閉包這個名詞是從《JavaScript權威指南》中讀到的,當時還是2015年的3月份,我剛開始看寒假購買的書,話說那時我還沒有和初戀分手,我清楚的記得我在從徐州回蘇州的火車上全程研究這本《JavaScript權威指南》的屌絲情境(異地戀),前女友說這本書封面上的犀牛醜死了,我說“你懂啥!”==|||
話不多說,經過一番回憶,我想起來閉包這個東西直到分手後的5個月裡都沒有搞清楚,直到某一天我在實驗室寫完了三段js代碼對比後,我了悟了這本神書的講的閉包思想!
先來看下閉包的百度百科,且看(配圖):
閉包是可以包含自由(未綁定到特定對象)變數的代碼塊;這些變數不是在這個代碼塊內或者任何全域上下文中定義的,而是在定義代碼塊的環境中定義(局部變數)。“閉包” 一詞來源於以下兩者的結合:要執行的代碼塊(由於自由變數被包含在代碼塊中,這些自由變數以及它們引用的對象沒有被釋放)和為自由變數提供綁定的計算環境(範圍)。
在 Scala、Scheme、Common Lisp、Smalltalk、Groovy、JavaScript、Ruby、 Python、Go、Lua、objective c、swift 以及Java(Java8及以上)等語言中都能找到對閉包不同程度的支援。
乍一看,百度說的神乎其神,什麼代碼塊,什麼局部變數,說白了,我們只要搞清js的代碼的一點原理:範圍的釋放和存在問題。
閉包(closure)是Javascript語言的一個痛點,也是它的特色,很多進階應用程式都要依靠閉包實現。
閉包有三個特性:
1.函數嵌套函數
2.函數內部可以引用外部的參數和變數
3.參數和變數不會被記憶體回收機制回收
對比下面三段代碼:
且看看下面代碼:
//全域變數的應用和變化Var GLOBAL = 1 //全域變數function change_global(){ var GLOBAL = 2; //重新定義了GLOBAL作為局部變數,不加var則變成了引用全域變數 alert(GLOBAL);}change_global();Alert(GLOBAL);
瀏覽器顯示:先2,後1。
結論:驗證了一點,函數改變了局部變數,但沒有改變全域變數,但是一旦去掉了局部變數GLOBAL前面的var那麼結果就是2,2。函數執行完後,函數的範圍鏈被銷毀,隨之局部變數被銷毀了!全域變數要等到頁面關閉(程式結束)被銷毀
如果很熟悉js文法和範圍鏈的,可以跳過上面的代碼,我是為了說下面的代碼!
且看下面代碼:
//z是個普通的function,執行一次範圍鏈就被銷毀var function z(t){ var s=[1,2,3]; //局部變數s s.push(t); //往s數組中添加數字 return s;}z(4); //執行後銷毀這次z(5); //執行後銷毀這次alert(z(6)); //執行後銷毀這次
瀏覽器顯示:1,2,3,6。
結論:4,5呢?當然是因為前兩次執行結束後函數被銷毀了,所以最後只有6被添加進去了,充分證明了js執行函數在記憶體中的原理——執行完就銷毀function中的一切!
上面的話不完全對,真的是一切嗎?
且看下面代碼:
//x這是個閉包函數,結束後會被銷毀,但是因為他返回了另一個函數,這個函數調用並返回了局部變數s,所以s不能被摧毀了,必須被保留下來!//x這是個閉包函數,結束後會被銷毀,但是因為他返回了另一個函數,這個函數調用並返回了局部變數s,所以s不能被摧毀了,必須被保留下來!function x(){ var s=[1,2,3]; //一樣的局部變數s return function(t){ s.push(t); //一樣往s中添加數字 return s; };}var y=x(); //閉包賦值給y變數y(4);y(5);alert(y(6));
瀏覽器顯示:1,2,3,4,5,6。
結論:function x()事實上是製作了一個只屬於代碼塊環境的閉包,閉包中的s變數是不會因為這個x執行完成後被銷毀,也不會因為返回的函數執行完後被銷毀,即使這段代碼全部執行完,s仍然保留在記憶體中,範圍鏈也仍然存在,知道程式結束(關閉瀏覽器)!所以注意:濫用閉包會導致記憶體不足的!
為了更好的說明,銷毀與不銷毀的問題,我推薦下面這段代碼
//全域對象y,當中的變數:程式結束前永遠不會銷毀//函數中的局部對象在函數結束後也會像變數一樣被銷毀的var y={ s:[1,2,3], //對象中的變數 //對象中的方法(類似於函數)add:function(t){ this.s.push(t); return this.s; }}y.add(4);y.add(5);alert(y.s);
瀏覽器顯示:1,2,3,4,5,6。
結論:用對象和閉包達到同樣的效果,因為對象除非指定銷毀,不然會存留在當前程式記憶體中!
使用閉包有一個優點,也是它的缺點,就是可以把局部變數駐留在記憶體中,可以避免使用全域變數。全域變數在每個模組都可調用,這勢必將是災難性的。
《JavaScript權威指南》學習——js閉包