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個元素建成堆。排序 輸出堆頂元素後,調整剩餘元素,使之成為大根堆 繼續輸 出堆頂,繼續調整,依此類推。一 篩選 調整堆使之成為大根堆或小根堆 輸出堆頂元素後,將堆底元素送入堆頂,由於根結點不滿足堆的性質,此時堆被破壞,而根結點的左右子樹仍然...