js的閉包,優缺點。
對於變量作用域的靈活使用;全局變量及局部變量。
js的特點:函數內部可以直接讀取全局變量,但是在函數外部無法讀取函數內部的局部變量。
閉包是為了完成,從外部讀取函數內部的局部變量。
function f1(){
var n = 999;
function f2(){
console.log(n);
}
}
想要獲取函數內部的局部變量的靈活處理方式就是,在函數內部再次定義一個函數。
函數外部無法讀取函數內部的內容,函數內部卻可以訪問到全局變量,也因此要獲取到函數內部的內容就是將定義一個函數將該函數變成該函數內部的定義函數。但是該內部函數的變量相對於父函數是不可見的。-js語言特有的鏈式作用域結構。(子對象會一級一級向上尋找所有父對象的變量。因此父對象的所有對象針對子對象都是可見的,但是子對象對於父對象是不可見的)
閉包的概念:f2函數就是一個閉包。閉包的作用就是能夠讀取其他函數的內部變量的函數。
js中只有函數內部的子函數才能讀取局部變量。閉包就是一個函數內部的子函數。閉包是連接函數內部和函數外部的橋梁。
閉包的作用:1.讀取函數內部的變量。2.讓變量的值一直保持在內存當中,不會再f1調用之后被自動清除。f1是f2的父函數,而f2被賦給一個全局變量,導致f2始終存在於內存中,而f2的存在依賴於f1所以f1始終在內存中,不會調用結束之后,被垃圾回收機制回收,garbage collection回收。
nAdd= function(){n+=1} 首先nAdd前面沒有使用var關鍵字,因此nAdd是一個全局變量,而不是局部變量。其次,nAdd的值是一個匿名函數,而匿名函數本身也是一個閉包,所以,nAdd相當於一個setter,可以在函數外部對函數內部的局部變量進行操作。
使用閉包需要注意:1.由於閉包會使得函數中的變量被保存在內存中,對內存消耗很大,因此不能濫用閉包,否則會造成頁面性能問題,在ie中可能導致內存泄漏問題。解決方法是,在退出函數之前,將不使用局部變量全部刪除。2.閉包會在父函數外部,改變父函數內部變量的值。所以,如果把父函數作為對象,把閉包當做公用方法,把內部變量當做他的私有屬性,這時一定要小心,不要隨意改變父函數內部變量的值。
js的垃圾回收:
js中,js的執行環境會負責管理代碼執行中的使用的內存,自動垃圾回收機制。
生命周期:當一個變量的生命周期結束之后,它所指向的內存就應該被釋放。js的兩種變量,全局變量和在函數中定義產生的局部變量。局部變量的生命周期在函數執行之后就結束了,此時就將其引用向內存釋放。但是全局變量會持續到瀏覽器關閉頁面。
js的垃圾回收方式:js執行環境中的垃圾回收器怎樣才能檢測哪塊內存可以被回收,主要是兩種方式,標記清除、引用計數。
標記清除:即函數執行時標記進入環境,函數執行完時,標記離開環境。在離開環境之后還有變量即標記方式不定,可以是某個特殊位的反轉或維護一個列表。
垃圾收集器給內存中的所有變量都加上標記,然后去掉環境中的變量以及被環境中的變量引用的變量標記。在此之后,再被加上的標記的變量即為需要回收的變量,因為環境中的變量已經無法訪問這些變量。
引用計數:這種方式可能會引起內存泄漏,在低版本的ie使用該方式。機制是跟蹤一個值得引用次數,當聲明一個變量並將一個引用類型賦值給該變量時該值引用次數加一,當這個變量指向其他一個時,該值得引用次數減一。當該值引用次數為0時,就會回收。
導致泄漏的原因是 不能解決循環引用的問題。(對象循環賦值,沒有使用中間值)
function s(){var a={};var b={};a.prop = b; b.prop=a;}
這種情況下,導致每次調用該函數,a和b的計數引用都是2,會使這部分內存永遠不會被釋放,即導致內存泄漏(內存無法被釋放或者使用,一直被占用。)