js閉包及垃圾回收機制和引起內存泄漏的操作

js變量作用域的特點和侷限

變量的作用域無非就兩種:全局變量和局部變量。
javascript語言的特別之處就在於:函數內部可以直接讀取全局變量,但是在函數外部無法讀取函數內部的局部變量。

閉包解決了什麼問題?

閉包的概念:“定義在一個函數內部的函數“
解決的問題:出於種種原因,我們有時候需要獲取到函數內部的局部變量。但是,上面已經說過了,正常情況下,這是辦不到的!只有通過變通的方法才能實現-那就是閉包。

function f1(){
    var n=999;
    function f2(){
      alert(n); // 999
    }

  }

閉包的用途

它的最大用處有兩個,一個是前面提到的可以讀取函數內部的變量,另一個就是讓這些變量的值始終保持在內存中,不會在f1調用後被自動清除。
使用場景:
(1)採用函數引用方式的setTimeout調用。
例子:
原生的setTimeout有一個缺陷,你傳遞的第一個函數不能帶參數。即

setTimeout(func(parma),1000);

這樣的語句是不生效的(不過在不同瀏覽器中有不同的錯誤,總之都無法達到預期效果)
這時,我們就可以用閉包來實現這個效果了。

function func(param) {
    return function() {
        alert(param);
    }
}
var f = func(1)
setTimeout(f, 1000);

(2)將函數關聯到對象的實例方法。

(3)封裝相關的功能集。

JS的垃圾回收機制瞭解嗎?

Js具有自動垃圾回收機制。垃圾收集器會按照固定的時間間隔週期性的執行。

JS中最常見的垃圾回收方式是標記清除

工作原理:是當變量進入環境時,將這個變量標記爲“進入環境”。當變量離開環境時,則將其標記爲“離開環境”。標記“離開環境”的就回收內存。

工作流程:

  1. 垃圾回收器,在運行的時候會給存儲在內存中的所有變量都加上標記。

  2. 去掉環境中的變量以及被環境中的變量引用的變量的標記。

  3. 再被加上標記的會被視爲準備刪除的變量。

  4. 垃圾回收器完成內存清除工作,銷燬那些帶標記的值並回收他們所佔用的內存空間。

引用計數方式

工作原理:跟蹤記錄每個值被引用的次數。

工作流程:

  1. 聲明瞭一個變量並將一個引用類型的值賦值給這個變量,這個引用類型值的引用次數就是1。

  2. 同一個值又被賦值給另一個變量,這個引用類型值的引用次數加1.

  3. 當包含這個引用類型值的變量又被賦值成另一個值了,那麼這個引用類型值的引用次數減1.

  4. 當引用次數變成0時,說明沒辦法訪問這個值了。

  5. 當垃圾收集器下一次運行時,它就會釋放引用次數是0的值所佔的內存。

但是循環引用的時候就會釋放不掉內存。循環引用就是對象A中包含另一個指向對象B的指針,B中也包含一個指向A的引用。

因爲IE中的BOM、DOM的實現使用了COM,而COM對象使用的垃圾收集機制是引用計數策略。所以會存在循環引用的問題。

解決:手工斷開js對象和DOM之間的鏈接。賦值爲null。IE9把DOM和BOM轉換成真正的JS對象了,所以避免了這個問題。

什麼情況會引起內存泄漏?

雖然有垃圾回收機制但是我們編寫代碼操作不當還是會造成內存泄漏。

  1. 意外的全局變量引起的內存泄漏。
    原因:全局變量,不會被回收。
    解決:使用嚴格模式避免。

  2. 閉包引起的內存泄漏
    原因:閉包可以維持函數內局部變量,使其得不到釋放。
    解決:將事件處理函數定義在外部,解除閉包,或者在定義事件處理函數的外部函數中,刪除對dom的引用。

  3. 沒有清理的DOM元素引用
    原因:雖然別的地方刪除了,但是對象中還存在對dom的引用
    解決:手動刪除。

  4. 被遺忘的定時器或者回調
    原因:定時器中有dom的引用,即使dom刪除了,但是定時器還在,所以內存中還是有這個dom。
    解決:手動刪除定時器和dom。

  5. 子元素存在引用引起的內存泄漏
    原因:div中的ul li 得到這個div,會間接引用某個得到的li,那麼此時因爲div間接引用li,即使li被清空,也還是在內存中,並且只要li不被刪除,他的父元素都不會被刪除。
    解決:手動刪除清空。

什麼放在內存中?什麼不放在內存中?

基本類型是:Undefined/Null/Boolean/Number/String

基本類型的值存在內存中,被保存在內存中。從一個變量向另一個變量複製基本類型的值,會創建這個值的一個副本。

引用類型:object

引用類型的值是對象,保存在內存中。

  1. 包含引用類型值的變量實際上包含的並不是對象本身,而是一個指向該對象的指針。從一個變量向另一個變量複製引用類型的值,複製的其實是指針,因此兩個變量最終都指向同一個對象。

  2. js不允許直接訪問內存中的位置,也就是不能直接訪問操作對象的內存空間。在操作對象時,實際上是在操作對象的引用而不是實際的對象。

棧和堆的區別

  一、堆棧空間分配區別:
  1、棧(操作系統):由操作系統自動分配釋放 ,存放函數的參數值,局部變量的值等。其操作方式類似於數據結構中的棧;
  2、堆(操作系統): 一般由程序員分配釋放,若程序員不釋放,程序結束時可能由OS回收,分配方式倒是類似於鏈表。
  二、堆棧緩存方式區別:
  1、棧使用的是一級緩存, 他們通常都是被調用時處於存儲空間中,調用完畢立即釋放;
  2、堆是存放在二級緩存中,生命週期由虛擬機的垃圾回收算法來決定(並不是一旦成爲孤兒對象就能被回收)。所以調用這些對象的速度要相對來得低一些。
  三、堆棧數據結構區別:
  堆(數據結構):堆可以被看成是一棵樹,如:堆排序;
  棧(數據結構):一種先進後出的數據結構。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章