1. 程式人生 > 程式設計 >詳解JavaScript堆疊與拷貝

詳解JavaScript堆疊與拷貝

一.堆疊的定義

1.棧是一種特殊的線性表。其特殊性在於限定插入和刪除資料元素的操作只能在線性表的一端進行。

詳解JavaScript堆疊與拷貝

結論:後進先出(Last InarZWsbGr First Out),簡稱為LIFO線性表。

棧的應用有:數制轉換,語法詞法分析,表示式求值等

2.佇列(Queue)也是一種運算受限的線性表,它的運算限制與棧不同,是兩頭都有限制,插入只能在表的一端進行(只進不出),而刪除只能在表的另一端進行(只出不進),允許刪除的一端稱為隊尾(rear),允許插入的一端稱為隊頭 (Front),佇列的操作原則是先進先出的,所以佇列又稱作FIFO表(First In程式設計客棧 First Out)。

詳解JavaScript堆疊與拷貝

由於棧和佇列也是線性表,棧和佇列有arZWsbGr順序棧和鏈棧兩種儲存結構,這兩種儲存結構的不同,則使得實現棧的基本運算的演算法也有所不同。

二.js堆疊研究

1、棧(stack)和堆(heap)

stack為自動分配的記憶體空間,它由系統自動釋放;而heap則是動www.cppcns.com態分配的記憶體,大小不定也不會自動釋放。

2、基本型別和引用型別

(1)基本型別:存放在棧記憶體中的簡單資料段,資料大小確定,記憶體空間大小可以分配。
5種基本資料型別有Undefined、Null、Boolean、Number 和 String,它們是直接按值存放的,所以可以直接訪問。

(2)引用型別:存放在堆記憶體中的物件,變數實際儲存的是一個指標,這個指標指向另一個位置。每個空間大小不一樣,要根據情況開進行特定的分配。

當我們需要訪問引用型別(如物件,陣列,函式等)的值時,首先從棧中獲得該物件的地址指標,然後再從堆記憶體中取得所需的資料。

3、傳值與傳址

前面之所以要說明什麼是記憶體中的堆、棧以及變數型別,實際上是為了更好的理解什麼是“淺拷貝”和“深拷貝”。
基本型別與引用型別最大的區別實際就是傳值與傳址的區別。測試用例:

var a = [1,2,3,4,5];
var b = a;
var c = a[0];
alert(b);//1,5 
alert(c);//1 
//改變數值         
b[4] = 6;
c = 7;
alert(a[4]);//6
alert(a[0]);//1

從上面我們可以得知,當我改變b中的資料時,a中資料也發生了變化;但是當我改變c的資料值時,a卻沒有發生改變。

這就是傳值與傳址的區別。因為a是陣列,屬於引用型別,所以它賦予給b的時候傳的是棧中的地址(相當於新建了一個不同名“指標”),而不是堆記憶體中的物件。而c僅僅是從a堆記憶體中獲取的一個數據值,並儲存在棧中。所以b修改的時候,會根據地址回到a堆中修改,c則直接在棧中修改,並且不能指向a堆記憶體中。

詳解JavaScript堆疊與拷貝

三.拷貝

1.淺拷貝

前面已經提到,在定義一個物件或陣列時,變數存放的往往只是一個地址。當我們使用物件拷貝時,如果屬性是物件或陣列時,這時候我們傳遞的也只是一個地址。因此子物件在訪問該屬性時,會根據地址回溯到父物件指向的堆記憶體中,即父子物件發生了關聯,兩者的屬性值會指向同一記憶體空間。

var a = {
         key1:"11111"
    }
function Copy(p) {
var c = {};
for (var i in p) { 
           c[i] = p[i];
        }
return c;
  }
     a.key2 = ['小輝','小輝'];
var b = Copy(a);
    b.key3 = '33333';
     alert(b.key1);     //1111111
     alert(b.key3);    //33333
     alert(a.key3);    //undefined

a物件中key1屬性是字串,key2屬性是陣列。a拷貝到b,12屬性均順利拷貝。給b物件新增一個字串型別的屬性key3時,b能正常修改,而a中無定義。說明子物件的key3(基本型別)並沒有關聯到父物件中,所以undefined。

b.key2.p程式設計客棧ush("大輝");
alert(b.key2);    //小輝,小輝,大輝
alert(a.key2);    //小輝,小輝,大輝

但是,若修改的屬性變為物件或陣列時,那麼父子物件之間就會發生關聯。從以上彈出結果可知,我對b物件進行修改,a、b的key2屬性值(陣列)均發生了改變。其在記憶體的狀態,可以用下圖來表示。

詳解JavaScript堆疊與拷貝

原因是key1的值屬於基本型別,所以拷貝的時候傳遞的就是該資料段;但是key2的值是堆記憶體中的物件,所以key2在拷貝的時候傳遞的是指向key2物件的地址,無論複製多少個key2,其值始終是指向父物件的key2物件的記憶體空間。

2.深度拷貝

或許以上並不是我們在實際編碼中想要的結果,我們不希望父子物件之間產生關聯,那麼這時候可以用到深拷貝。既然屬性值型別是陣列和或象時只會傳址,那麼我們就用遞迴來解決這個問題,把父物件中所有屬於物件的屬性型別都遍歷賦給子物件即可。測試程式碼如下:

function Copy(p,c) {
var c = c || {};
for (var i in p) {
if (typeof p[i] === 'object') {
              c[i] = (p[i].constructor === Array) ? [] : {};
             Copy(p[i],c[i]);
           } else {
              c[i] = p[i];
          }
        }
return c;
  }    
     a.key2 = ['小輝','小輝'];
var b={};
     b = Copy(a,b);        
     b.key2.push("大輝");
     alert(b.key2);    //小輝,小輝,大輝
     alert(a.key2);    //小輝,小輝

由上可知,修改b的key2陣列時,沒有使a父物件中的key2陣列新增一個值,即子物件沒有影響到父物件a中的key2。其儲存模式大致如下:

詳解JavaScript堆疊與拷貝

以上就是詳解javascript堆疊與拷貝的詳細內容,更多關於JS 堆疊 拷貝的資料請關注我們其它相關文章!