概念:閉包是指有權訪問另外一個函數做用域中的變量的函數。下面的outer就造成了一個閉包:
function outer(){ const name='nagi'; return function inner(){ console.log(name); } } let p=outer(); } let p=outer();
通常來說,當函數執行完畢後,局部活動對象就會被銷燬,內存中僅保存全局執行環境中的變量對象,但閉包有所不一樣。
當outer()執行完後,由於inner函數的做用域鏈在引用outer的活動對象,因此它並不會被銷燬,而是仍然留在內存中,
除非inner函數也銷燬它的活動對象纔會被銷燬。好比使p=null;git
特性: 由上面的代碼能夠得出如下幾個特性:github
a. 函數嵌套函數,做爲一個函數變量的一個引用,當函數返回時,其處於激活狀態。 b. 函數內部能夠引用外部的參數和變量。 c. 一個閉包就是當一個函數返回時,一個沒有釋放資源的棧區,因此參數和變量不會被垃圾回收機制回收。
優勢:閉包
a. 減小全局變量的污染 b. 能夠有私有變量的存在
function counter(){ let n=0; function add(){ n++; console.log(n); } return {n:n, add:add} } const c1=counter(); const c2=counter(); // 它和c1分別存入了不一樣的堆內存中 c1.add(); // 1 c1.add(); // 2 c1.n; // 0 // 此處的n是基本類型,除非從新賦值,不然不會變! c2.add(); // 1 c1和c2互不干涉,都有本身的新的做用域鏈和新的私有變量 注意!!父函數每次調用會產生新的閉包
缺點(問題):函數
a.常駐內存,增長內存使用量。 b. 使用不當會很容易形成內存泄露。
另:閉包的多種寫法能夠參照這裏: JavaScript閉包(closure)
原理:js中有自動回收管理內存機制,它的原理是會按期(週期性地)找出那些再也不繼續使用的變量,而後釋放其佔用的內存。
內存管理:指針
1. 分配內存(無論是基本類型仍是引用類型) 2. 使用內存(對變量,函數等讀取或寫操做) 3. 釋放內存(使用垃圾回收機制回收內存)
**含義:**跟蹤記錄每一個值被引用的次數。 **工做機制:** 當聲明一個變量並將一個引用類型值賦給它時,則這個值的引用次數就是1; 若是同一個值又被賦給另外一個變量,則該值的引用次數加1; 相反,若是包含對這個值引用的變量又被賦了其餘值,則這個值的引用次數減1; 當這個值的引用次數爲0時,則說明沒有辦法再訪問這個值了; 這樣,當垃圾收集器下次再運行時,便會釋放這種引用次數爲0的值所佔的內存。
問題:code
這種方式有一個嚴重的問題,即「循環引用」。 意思是對象A中包含一個指向對象B的指針,而對象B也包含一個指向對象A的指針, 這樣當函數執行完畢後,由於其引用也就永遠不會爲0,因此對象A和B將繼續存在, 若是對象所在函數被重複調用,就會致使大量內存得不到回收。
function problem(){ let objA=new Object(); let objB=new Object(); objA.someOtherObj=objB; objB.antherObj=objA; }
原理:垃圾回收器會在運行時給存儲在內存中的全部變量加一個標記。 (當變量進入環境時,就交這個變量標記爲「進入環境」。而當變量離開環境時,則將其標記爲「離開環境」。) 而後,它會去掉環境中的變量以及被環境中的變量引用的變量的標記(閉包)。 而在這些完成以後再被加上標記的變量將被視爲準備刪除的變量,緣由是環境中的變量已經沒法訪問到這些變量了。 最後,垃圾回收器完成內存清除工做,銷燬那些帶標記的值並回收它們所佔用的內存空間。