關(guān)于對象的深淺拷貝氯材,個人有以下幾點見解:
1.深拷貝和淺拷貝只針對像Object, Array這樣的引用類型數(shù)據(jù)渔彰。
2.淺拷貝是對對象引用地址進行拷貝,并沒有開辟新的棧新蟆,也就是拷貝后的結(jié)果是兩個對象指向同一個引用地址勘天,修改其中一個對象的屬性怔揩,則另一個對象的屬性也會改變。
3.深拷貝則是開啟一個新的棧脯丝,兩個對象對應(yīng)兩個不同的引用地址商膊,修改一個對象的屬性,不會改變另一個對象的屬性巾钉。
image.png
image.png
真-深拷貝
看著深淺拷貝翘狱,區(qū)別寫法很簡單秘案,但是那個上面的深拷貝寫法是有問題的砰苍×市伲看下面案例:
var arr=[{a:1,b:2},{a:3,b:4}]
var newArr=Object.assign([],arr)
//截斷數(shù)組
newArr.length=1
console.log(newArr)//[{a:1,b:2}]
console.log(arr)//[{a:1,b:2},{a:3,b:4}]
//操作newArr,這里看著對arr沒影響赚导,實際上已經(jīng)挖了一個坑茬缩,下面就跳進去
newArr[0].a=123
//修改newArr[0]這個對象,也是影響了arr[0]這個對象
console.log(arr[0])//{a: 123, b: 2}
為什么會這樣呢吼旧,因為Object.assign并不是深拷貝凰锡,是披著深拷貝外衣的淺拷貝。最多也是Object.assign會課拷貝第一層的值圈暗,對于第一層的值都是深拷貝掂为,而到第二層的時候就是 復(fù)制引用。類似的情況還有员串,slice方法和concat方法等勇哗。要解決這個問題,就得自己封裝方法寸齐!如下:
//利用遞歸來實現(xiàn)深拷貝欲诺,如果對象屬性的值是引用類型(Array,Object),
//那么對該屬性進行深拷貝渺鹦,直到遍歷到屬性的值是基本類型為止扰法。
function deepClone(obj){
if(obj === null) return null
if(typeof obj !== 'object') return obj;
if(obj.constructor===Date) return new Date(obj);
if(obj.constructor === RegExp) return new RegExp(obj);
var newObj = new obj.constructor (); //保持繼承鏈
for (var key in obj) {
if (obj.hasOwnProperty(key)) { //不遍歷其原型鏈上的屬性
var val = obj[key];
newObj[key] = typeof val === 'object' ? arguments.callee(val) : val; // 使用arguments.callee解除與函數(shù)名的耦合
}
}
return newObj;
}
// 測試
var arr=[{a:1,b:2},{a:3,b:4}]
var newArr=deepClone(arr)
console.log(arr[0])//{a:1,b:2}
newArr[0].a=123
console.log(arr[0])//{a:1,b:2}
還有一個方法就是簡單粗暴法,我現(xiàn)在在用的一個方法毅厚!原理很簡單塞颁,就是先把對象轉(zhuǎn)成字符串,再把字符串轉(zhuǎn)成對象吸耿!也能實現(xiàn)同樣效果殴边。
var newArr2=JSON.parse(JSON.stringify(arr));
console.log(arr[0])//{a:1,b:2}
newArr2[0].a=123
console.log(arr[0])//{a:1,b:2}
jquery 中$.extend()也可以實現(xiàn)深拷貝
$.extend( [deep ], target, object1 [, objectN ] )
- deep
類型: Boolean
如果是true,合并成為遞歸(又叫做深拷貝)珍语。- target
類型: Object
對象擴展锤岸。這將接收新的屬性。- object1
類型: Object
一個對象板乙,它包含額外的屬性合并到第一個參數(shù)是偷。- objectN
類型: Object
包含額外的屬性合并到第一個參數(shù)。
參考網(wǎng)址: