首頁  >  文章  >  web前端  >  JavaScript中關於變數作用域和記憶體問題的理解

JavaScript中關於變數作用域和記憶體問題的理解

php是最好的语言
php是最好的语言原創
2018-08-03 10:17:571081瀏覽

變數作用域與記憶體問題

1.基本型別與參考型別的值

基本型別就是簡單的資料段(5種值型別),而參考型別就是物件(操控物件的引用)。

1.1複製變數值

引用型別實際上在複製的時候,傳遞的是函數的指針,複製完成後,實際兩個變數所引用的都是同一個堆記憶體中的對象,改變這個對象,兩個變數的值也會同步改變。

1.2傳遞參數

函數的參數都是由值傳遞的。其實我認為這種說法多少還是有點抽象。總結起來不如這樣說。當傳遞給函數的變數是值型別時,那麼傳遞給函數的這個原始變數的就不會隨函數內部的影響而改變。當傳遞給函數的變數是引用型別(object)時,那麼傳遞給函數的這個原始變數的引用就不會隨函數內部的影響而改變。其實這裡不是太容易理解,例如舉個例子來說明

        var obj = {
            name: 'andy'
        }

        function ChangeObj(val) {
            val.age = '25'
            val = {
                name:'zakas',
                age:40
            }
            return val;
        }
        ChangeObj(obj); // {name:'zakas',age:40}
        console.log(obj) // {name:'andy',age:25}

上面這個例子中,函數中val的記憶體位址變了(引用變了),如果函數是按引用傳遞的話,那麼val的引用就是obj的引用,val的應用改變了,obj的引用也會跟著變化,所以obj的結果也應該是{name:'zakas',age:40}。而按值傳遞的話,obj賦值給val它的引用,但是他兩個的引用是不關聯在一起的,val引用的改變並不會影響obj的引用位址。

函數的形參就是函數作用域中的局部變數。當函數運行完是會被銷毀的。

1.3偵測類型

instanceof 可以進行引用型別的更明確的偵測。所以值型別在instanceof總全是false,值型別也沒必要用其方法來偵測。 instanceof只能區分Array Object 和 RegExp

2.執行環境

每個執行環境都有一個變數物件,變數物件的概念很重要。它是作用域中所有定義的變數的一個大的集合;每個執行環境都有一個變數物件,儲存著我們定義的所有變量,但是這個變數物件我們存取不到,但解析器處理資料時會在背景使用它。

    function A() {
        var tempA;
        function B() {
            var tempB;
            function C() {
                var tempC
            }
        }
    }

B()的作用域鏈中包含3個對象,一個是自己的變數對象,還有A的變數對象和全域變數對象。 A()中的作用域鏈包含2個對象,一個A()自己的變數對象,還有就是全域變數對象。因此A訪問不了B的變量,只能存取自己的和全域的變數。但B不但能存取自己的變量,也能存取A和全域作用域下的變數。

2.1延長作用域鏈

with

With相當於創造了一個新的變數物件在目前作用域的上方。例如:

    var obj = {
        name:'andy',
        sex:'man',
        hobby:'game'
    }
    function fn() {
        with(obj) {
            fnName = name;
            fnSex = sex;
            fnHobby = hobby;
        }
        console.log(fnName,fnSex,fnHobby) // andy,man,game
    }
    fn()

With方法會造成性能的嚴重損失,所以一般不建議用

2.2無區塊級作用域

必須知道這個概念,作用和區別,最老生常談的一個問題:

for(var i =0 ; i < 10 ; i++ ) {
    setTimeout(function(){
        console.log(i);
    },0)
}

在理解這個問題的前提下,首先要知道定時器是異步的,即使是0,也要先放到緩存區中,當其他程式自上而下執行完畢之後再去調用。所以在其他程式自上而下執行完畢之後,由於沒有區塊級作用域,i是全域的,已經變成10了,所以輸出10個10。如果把i改為存在塊級作用域的let,那麼問題就迎刃而解了。

for(let i =0 ; i < 10 ; i++ ) {
    setTimeout(function(){
        console.log(i);
    },0)
}

2.3垃圾收集

JavaScript具有自動垃圾收集機制

使用值的過程中,其實是相當於變數分配的記憶體進行寫入和讀取的操作。 JavaScript在創建變數的過程會分配內存,當變數不用時會自動釋放掉,這個過程叫做垃圾回收機制,但是這個自動是混亂的根源,很多開發者因此覺得不用太關心內存問題,這是錯誤的。

原理:垃圾處理器會在預設情況下週期的進行偵測,找出那些不使用的變量,然後釋放其記憶體。
回收策略:在局部環境中,函數調用完之後,垃圾收集器會追蹤哪個變數有用,哪個變數沒有用,對於沒用的變量,打上標記,以備回收其內存,但是標記的方法通常有另兩個策略:

  • 標記清除:從2012年起,所有瀏覽器全部使用標記清除的方法進行垃圾回收,並且所有對js垃圾回收的改進也是基於標記清除的方法進行演算法最佳化。

  • 引用計數:這個由於有嚴重的循環引用問題,所以現在已經基本上不用了。

因此,當寫入的程式佔用較少的記憶體是高效能頁面的一個很重要的點。所以當我們寫程式時候,一旦資料不用了,最好設定成null來解除引用

#相關文章:

JavaScript變數作用域和內存問題(二)

#

李炎恢Javascript影片教學

以上是JavaScript中關於變數作用域和記憶體問題的理解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn