JS堆疊與拷貝

2022-05-01 16:15:11 字數 3418 閱讀 9955

一.堆疊的定義

結論:後進先出(last in first out),簡稱為lifo線性表。

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

2.佇列(queue)也是一種運算受限的線性表,它的運算限制與棧不同,是兩頭都有限制,插入只能在表的一端進行(只進不出),而刪除只能在表的另一端進行(只出不進),允許刪除的一端稱為隊尾(rear),允許插入的一端稱為隊頭 (front),佇列的操作原則是先進先出的,所以佇列又稱作fifo表(first in first out)。

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

二.js堆疊研究

1、棧(stack)和堆(heap)

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

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,2,3,4,5

alert(c);//

1 //

改變量值

b[4] = 6;

c = 7;

alert(a[4]);//

6alert(a[0]);//

1

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

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

三.拷貝

1.淺拷貝

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

var a =

function

copy(p) ;

for (var i in

p) 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.push("大輝");

alert(b.key2);

//小輝,小輝,大輝

alert(a.key2); //

小輝,小輝,大輝

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

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

2.深度拷貝

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

function

copy(p, c) ;

for (var i in

p) ;

copy(p[i], c[i]);

} else

}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。其儲存模式大致如下:

js深拷貝與淺拷貝

1 基礎知識 基本型別與引用型別 js中可以把變數分成兩部分,基本型別和引用型別。基本型別包括 undefined null boolean number和string 引用型別值可能由多個值構成的物件。在對基礎型別資料進行拷貝時,實際相當於建立新的相同資料 hello 賦值給b var a hel...

js 淺拷貝與深拷貝

js 有兩種資料型別,基礎資料型別和引用資料型別 基礎資料型別都是按值訪問的,我們可以直接操作儲存在變數中的實際的值。而引用型別如array,1.淺拷貝 只複製指向某個物件的指標,而不複製物件本身,新舊物件共享一塊記憶體 淺拷貝是指只複製一層物件,當物件的屬性是引用型別時,實質複製的是其引用,當引用...

js深拷貝與淺拷貝

實現乙個頁面或者乙個功能時,常常遇到的場景需要我們備份乙個陣列或者物件,這時候出現了深拷貝與淺拷貝效果截然不同呀總結如下 var arr 1,2,3,4 shallowarr arr arr 0 change console.log arr console.log shallowarr change...