js深度拷貝和淺度拷貝的深入理解

2021-09-11 20:21:39 字數 4116 閱讀 2744

首先我們來說說什麼是拷貝:就是複製的同時加上了傳值。

然後問題就來了什麼是有深度的什麼是淺度的,在想要了解我們這個問題之前我們先來了解一下下面的乙個知識點

基本型別傳遞,引用型別傳遞

首先我們來看下基本型別傳遞:就是基本資料型別之間的資料傳遞,什麼是基本資料型別呢?string,number,boolean,null,undefined

他們這些型別的值發生傳遞的時候是將自己複製了乙份,吧賦值的哪乙份傳遞給了莫乙個變數;

引用型別傳遞:就是引用型別的值的的乙個傳遞,那麼什麼是引用型別呢?就是物件(object,arrey,regexp,function),他們都是物件,物件之間的賦值就不會吧自己複製乙份,為什麼呢?你想想假設每乙個物件都是乙個很大的房間,我們要把所有房間裡的東西都複製乙份,和房間裡面的小物品都要按原來的方式擺好來是不是太耗費時間了,所以在物件之間的傳輸,只是賦值了鑰匙(指標),就是我們都有了這個房間的鑰匙,所以就會出現大家可能知道的引用型別之間的傳遞的時候其中乙個改變,另乙個也會發生改變

當你們看懂了上面的之後我們就來分析一下上面是深度的什麼是淺度的

淺拷貝是拷貝一層,深層次的物件級別的就拷貝引用;深拷貝是拷貝多層,每一級別的資料都會拷貝出來;『/

下面我們就來些一些方法來看下如何實現深度拷貝?

那麼如何實現呢?可能大家一時間想不起來?那就對了,那就看下下面的這個例子

var obj1 = ;

var obj2 = ;

obj2.b = 100;

console.log(obj1);

// <-- b 沒被改到

console.log(obj2);

//

有人看了就奇怪了為什麼這樣就沒關係了呢?為什麼?想一想?

對沒錯就是這樣:因為obj1.a 這個值它是乙個基本型別,當我們在一次改變這個obj1.a這些基本型別值的時候是改變的他們的複製的副本,所以就沒關係了?對不對啊?

沒錯?其實還是有一定問題?什麼問題呢?如果我們ibj1.a他還是乙個物件,那麼他就還是乙個引用型別那麼我們不就還是不可以嗎對把?嗯是的還是不可以?

那麼我們需要幹上面呢?就是要把物件改為基本型別;

var obj = {}

var a = ,

}

這個例子中:如是可以的obj.b = a.b,但是obj.c = a.c 這個是不可以的因為a.c還是乙個物件,那麼現在obj.c還是乙個鑰匙,他改變了值,原來的a物件還是會改變,所以a.c這個物件還要在分變成obj.c.d = a.c.d 這樣就可以了,那麼怎麼分呢?用遞迴

// arguments.callee 當前函式

function deepclone(initaobj, finalobj) ;

for (var i in initaobj) ;

arguments.callee(initaobj[i], obj[i]);

} else

}return obj;

}

arguments.callee():表示呼叫的函式本身,為什麼用這個不用deepclone()這個呢?減少耦合性,當要改變函式名的時候,就可以少改一次

這樣就可以達到把物件中的屬性值中的物件在分一遍?

但是有沒有想過**中的一些問題

1.obj[i] = (initaobj[i].constructor === array) ? : {}; 這一行**的作用是什麼

我來告訴大家因為有可能屬性值是乙個陣列同時也可能是陣列,為了確保拷貝是一樣就這樣了

2.輸出的值是什麼

var obj = {};

var a = ,

e: [2, 3, 4, 5]

}console.log(deepclone(a, obj));

假設加上什麼的**執行會輸出和和a物件一樣的值,看上去對了,我們的目的就是要複製乙個和他一樣的值,但是他們雖然他們值是一樣的但是可以確保他們不是同乙個房子,而是我們需要的兩個房子呢?我們只需要改變obj中的屬性值看下a中的會不會也隨著發生改變就可以了,答案是不會的( 測試下),所以是對了

, e: array(4)}

a: 2

b: e: (4) [2, 3, 4, 5]

__proto__: object

obj.a = 2

a.a = 1

其實也就是每下項都是一基本型別的值傳給新的物件,但是是一層一層的傳,同時要注意是不是陣列,(其實還有其他的但是目前不考慮,比如函式)

3.下乙個問題就是還有乙個情況就是遇到了屬性值是函式function怎麼辦?答案是可以的

為什麼呢?我把我的理解寫一下:函式的這個房間,和陣列和物件的區別是函式這個房間他是不可以改變,他會自己執行完了自己毀滅,防止記憶體洩漏(佔了太多沒用的記憶體,整體的記憶體洩漏了)

首先 typeof function !== object 而是等於 function 執行上面的函式obj[i] = initaobj[i];那麼新的物件你某乙個屬性他也會變成了乙個(鑰匙)指標,這個函式的房間是沒辦法去改變的,你去改變只是換了給鑰匙,或者說是變成了基本型別的值,原來需要給你複製的物件的某乙個屬性,它還是拿的開啟那個房間的鑰匙(還是那個函式的指標,指向那個函式,隨時執行) ,所以是可以的

4.當舊值,等於新值怎麼辦?(在迭代中要思考的問題)那麼用這個就會無限迴圈,所以我們可以加這一行**

幾乎不會出現的情況

function deepclone(initalobj, finalobj) ;    

for (var i in initalobj)

if (typeof prop === 'object') ;

arguments.callee(prop, obj[i]);

} else

}

return obj;

}

其實還有乙個很好的方法

我們去想一下為什麼我們不可以把這個物件直接賦值,因為他是引用型別,不是基本型別,那麼其實我們可以先把他整體變成基本型別去賦值就可以了,最後在轉成為引用型別就可以了

var obj1 =  };

var obj2 = json.parse(json.stringify(obj1));

console.log(typeof obj1.fun);

// 'function'

console.log(typeof obj2.fun);

// 'undefined' <-- 沒複製

但是這個方法有2點不好

1.就是要用json的格式,屬性值不可以用function 但是可以把他賦值去了

2.譬如它會拋棄物件的constructor。也就是深拷貝之後,不管這個物件原來的建構函式是什麼,在深拷貝之後都會變成object。

第三種

繼承的方法(如果不了解繼承可以跳過)

function deepclone(initalobj, finalobj) ;

for (var i in initalobj)

if (typeof prop === 'object')

} else

}return obj;

}

object.create(prop);的作用是什麼?

object.create()方法建立乙個新物件,使用現有的物件來提供新建立的物件的__proto__。 ---mdn

所以作用就繼承了上一層的值,也達到了效果obj[i]繼承了prop的屬性值,當他去改變的時候,只是新增加他自己的屬性值,而

他繼承的屬性,的屬性值他是改變不了的,所以也是帶到了效果

第4種

用jquery 和 lodash 的函式框架

好了這個內容就到這裡了 如果文中有什麼錯誤,可以來和我說一下,嘿嘿

深度拷貝和淺度拷貝

文字說明 比如乙個陣列 array 淺度拷貝是當陣列a變數成陣列b的時候,b改變裡面的陣列數值的時候,a也隨著改變,深度拷貝是噹噹陣列a變數成陣列b的時候,b改變裡面的陣列數值的時候,a裡面的陣列陣列不隨著改變,那麼為什麼淺度拷貝會改變a的陣列值而深度拷貝則不會呢?因為淺度拷貝指向的是同乙個記憶體,...

js深度拷貝與淺度拷貝

如果你想真正自己理解和運用深度轉殖的話,首先必須要了解的就是js中的原始值和引用值,以及它們的儲存位置及方式。這裡簡單的說一下,原始值是儲存在棧裡的,而且儲存的是變數的實際值。引用值儲存在堆裡,且儲存的是乙個指標,該指標指向記憶體中的某個位置,該位置儲存變數的實際值。var a 2 var a co...

js中的淺拷貝深拷貝深入理解

舉個例子來說明一下什麼是淺拷貝什麼是深拷貝 var x c 1,2,3 var y shallow x 得出的結果可以看出是淺拷貝 出現這種情況的本質是 物件是按引用賦值的 指的是拷貝乙個物件,改變乙個值不影響另乙個的值 實現深複製功能 判斷 1.是否是物件 2.是否是函式 function dee...