JavaScript必學之資料深淺拷貝

2021-09-24 20:32:55 字數 4167 閱讀 9651

js 物件賦值之淺拷貝深拷貝在實際中應用

我們有時候有這樣的需求,需要將乙個值賦值給另外乙個變數。例如:

var a =10;

var b = a;

在這裡我們首先需要知道基本型別和引用型別的區別。js 有 6 種基本資料型別:undefined、null、boolean、number、string、symbol。引用型別有 array、date、function、(boolean、string…),他們都是複雜資料型別 object 的例項物件。基本資料型別是直接存放於棧記憶體中,可直接訪問。引用型別存放在堆記憶體中儲存的是乙個指標,當直接賦值時,會指向同乙個記憶體空間。

首先我們看基本資料型別賦值前後操作:

var a =10;

var b = a;

b =5

;console.

log(b)

;// 5

console.

log(a)

;// 10

從這裡可以看出雖然把 a 的值賦值給了 b,但是對 b 修改時並不會影響到 a。也就是說,他們儲存在單獨的空間裡。

再看引用型別賦值前後操作:

var obj =

;var newobj = obj;

newobj.a =

"aaa"

;console.

log(obj)

;//

console.

log(newobj)

;//

從這裡可以看出,修改賦值後的 newobj,原來的 obj 也發生了改變。可見他們指向的是同一片記憶體位址。

在實際應用中經常會有賦值的操作,如果不想影響到之前的資料就需要使用淺拷貝或者深拷貝。

1.淺拷貝

除了上面的直接賦值,還可以使用 object.assign()進行淺拷貝。

例如:

var obj =

;var assobj = object.

assign

(, obj)

;assobj.a =

"aaa"

;console.

log(obj)

;//

console.

log(assobj)

;//

對 object.assign()拷貝後的資料進行更改,不會改變原來物件裡的值。那麼為什麼它是淺拷貝而不是深拷貝呢,因為 object.assign()只能深拷貝第一層資料。

例如:

var obj =}}

;var assobj = object.

assign

(, obj)

;assobj.bbb =

"bbbb"

;assobj.ccc.c =

"cccc"

;assobj.ccc.oo.sss =

"sss"

;console.

log(obj)

;// } }

console.

log(assobj)

;// } }

上例可以看出對拷貝後的資料進行修改,雖然第一層資料來源物件沒有被修改,但是一層以外的資料被修改了。所以 object.assign()只能深度複製一層物件資料。

使用 json.parse(json.stringify(obj))進行深拷貝。

var obj =}}

;var jsonobj =

json

.parse

(json

.stringify

(obj));

jsonobj.bbb =

"bbbb"

;jsonobj.ccc.c =

"ccc"

;jsonobj.ccc.oo.sss =

"sss"

;console.

log(obj)

;// } }

console.

log(jsonobj)

;// } }

上例可以看到使用 json.parse(json.stringify())對進行拷貝的物件修改,所有層級的物件都沒有影響到源物件。所以可以說 json.parse(json.stringify())是深拷貝方法。

為什麼我描述為「可以說」,因為物件裡的值可以為任意引用型別。比如:array、date、function、boolean、string…

var obj =},

foo:

function()

, date:

newdate()

, boolean:

false

, arr:[1

,2,3

,4,5

,6,7

],exp:

newregexp

("e")}

;var jsonobj =

json

.parse

(json

.stringify

(obj));

jsonobj.bbb =

"bbbb"

;jsonobj.ccc.c =

"ccc"

;jsonobj.ccc.oo.sss =

"sss"

;console.

log(obj)

;/* },

foo: [function: foo],

date: 2019-05-28t08:42:05.454z,

boolean: false,

arr: [ 1, 2, 3, 4, 5, 6, 7 ],

exp: /e/

}*/console.

log(jsonobj)

;/* },

date: '2019-05-28t08:42:05.454z',

boolean: false,

arr: [ 1, 2, 3, 4, 5, 6, 7 ],

exp: {}

}*/

從上例可以看出,雖然對拷貝後的值改變物件屬性值源物件內值沒變,但是源物件裡的 function 型別和正規表示式資料卻沒有拷貝過來。

要達到真正意義上的深拷貝,需要手寫遞迴函式。

function

deepclone

(obj)

var objclone = array.

isarray

(obj)?[

]: object.prototype.tostring.

call

(obj)

==="[object object]"

?: obj.

valueof()

;if(obj &&

typeof obj ===

"object"

)else}}

}return objclone;

}var deep =

deepclone1

(obj)

;deep.bbb =

"bbbb"

;deep.ccc.c =

"ccc"

;deep.date =

newdate

("2018-10-09");

console.

log(obj);/*

}, foo: [function: foo],

date: 2019-05-29t02:43:12.332z,

boolean: false,

arr: [ 1, 2, 3, 4, 5, 6, 7 ],

exp: /e/ }

*/console.

log(deep);/*

}, foo: [function: foo],

date: 2018-10-09t00:00:00.000z,

boolean: false,

arr: [ 1, 2, 3, 4, 5, 6, 7 ],

exp: /e/ }

*/

總結:實際應用中會有很多地方需要對物件進行拷貝。這時候就要看情況使用淺拷貝還是深拷貝。在上文中,能夠了解到的知識點有淺拷貝深拷貝以及手寫深拷貝方法。

Anroid必學之BaseAdapter介面卡

導過包出來的四個方法。override public int getcount override public object getitem int i override public long getitemid int i 最最最重要的方法,這才是主要寫邏輯的方法 override public...

必學經典演算法之 氣泡排序

氣泡排序屬於交換類排序,兩兩比較,而後交換。排序過程如下 首先對位置0 n的資料從左到右兩兩比較,大的放後面,經過一輪的操作,n位置存放的是最大的數字 之後對位置0 n 1的資料從左到右兩兩比較,大的放後面,經過一輪的操作,n 1位置存放的是最大的數字 以此類推。o n 2 對於乙個int陣列,請編...

必學經典演算法之 堆排序

n個元素的序列,當且僅當滿足以下關係時,稱之為堆。建堆 將n個元素建成堆。排序 輸出堆頂元素後,調整剩餘元素,使之成為大根堆 繼續輸 出堆頂,繼續調整,依此類推。一 篩選 調整堆使之成為大根堆或小根堆 輸出堆頂元素後,將堆底元素送入堆頂,由於根結點不滿足堆的性質,此時堆被破壞,而根結點的左右子樹仍然...