淺拷貝
var obj = {a: 1, b: {c: 2}}
var obj1 = obj
var obj2 = shallowCopy(obj);
function shallowCopy(src) {
var dst = {};
for (var prop in src) {
if (src.hasOwnProperty(prop)) {
dst[prop] = src[prop];
}
}
return dst;
}
var obj3 = Object.assign({}, obj)
obj.a = 2
obj.b.c = 3
console.log(obj) // {a: 2, b: {c: 3}}
console.log(obj1) // {a: 2, b: {c: 3}}
console.log(obj2) // {a: 1, b: {c: 3}}
console.log(obj3) // {a: 1, b: {c: 3}}
這段代碼可以說明賦值得到的對象 obj1 只是將指針改變,其引用的仍然是同一個對象慌核,而淺拷貝得到的的 obj2 則是重新創(chuàng)建了新對象疆拘。但是,如果原對象obj中存在另一個對象箫踩,則不會對對象做另一次拷貝,而是只復制其變量對象的地址谭贪。這是因為淺拷貝只復制一層對象的屬性境钟,并不包括對象里面的為引用類型的數(shù)據(jù)。
對于數(shù)組俭识,更長見的淺拷貝方法便是slice(0)
和 concat()
ES6 比較常見的淺拷貝方法便是 Object.assign
深拷貝
通過上面的這些說明慨削,相信你對深拷貝大致了解了是怎樣一個東西了:深拷貝是對對象以及對象的所有子對象進行拷貝。那么如何實現(xiàn)這樣一個深拷貝呢鱼的?
- JSON.parse(JSON.stringify(obj))
對于常規(guī)的對象理盆,我們可以通過JSON.stringify來講對象轉成一個字符串,然后在用JSON.parse來為其分配另一個存儲地址凑阶,這樣可以解決內(nèi)存地址指向同一個的問題:
var obj = {a: {b: 1}}
var copy = JSON.parse(JSON.stringify(obj))
obj.a.b = 2
console.log(obj) // {a: {b: 2}}
console.log(copy) // {a: {b: 1}}
但是 JSON.parse()猿规、JSON.stringify也存在一個問題,JSON.parse()和J SON.stringify()能正確處理的對象只有Number宙橱、String姨俩、Array等能夠被 json 表示的數(shù)據(jù)結構,因此函數(shù)這種不能被 json 表示的類型將不能被正確處理师郑。
var target = {
a: 1,
b: 2,
hello: function() {
console.log("Hello, world!");
}
};
var copy = JSON.parse(JSON.stringify(target));
console.log(copy); // {a: 1, b: 2}
console.log(JSON.stringify(target)); // "{"a":1,"b":2}"
- 遍歷實現(xiàn)屬性復制
既然淺拷貝只能實現(xiàn)非object第一層屬性的復制环葵,那么遇到object只需要通過遞歸實現(xiàn)淺拷貝其中內(nèi)部的屬性即可:
function extend (source) {
var target
if (typeof source === 'object') {
target = Array.isArray(source) ? [] : {}
for (var key in source) {
if (source.hasOwnProperty(key)) {
if (typeof source[key] !== 'object') {
target[key] = source[key]
} else {
target[key] = extend(source[key])
}
}
}
} else {
target = source
}
return target
}
var obj1 = {a: {b: 1}}
var cpObj1 = extend(obj1)
obj1.a.b = 2
console.log(cpObj1) // {a: {b: 1}}
var obj2 = [[1]]
var cpObj2 = extend(obj2)
obj2[0][0] = 2
console.log(cpObj2) // [[1]]