JavaScript對象深拷貝
引言
在JavaScript中對對象拷貝複製通常是使用循環遍歷的方式:
var obj = {
x:1,
y:[1,2,3]
}
var obj2 = {};
for(let key in obj){
obj2[key] = obj[key];
}
obj.x = 10;
obj.y[0] = 4;
console.log(obj,obj2);
雖然obj2和obj輸出的結果看起來是一樣的,但當obj.y發生改變,obj2也會改變,因爲引用類型賦值的是地址,這種複製方式一般稱爲淺拷貝。那麼如何實現深度拷貝呢?下面介紹幾種JavaScript中常見的深拷貝的方式。
一、序列化、反序列化
通過JSON.parse和JSON.stringify
var obj = {
x:1,
y:[1,2,3]
}
var obj2 = JSON.parse(JSON.stringify(obj)); // 先轉爲json字符串,再轉回對象
obj.x = 10;
obj.y[0] = 4;
console.log(obj,obj2);
但是通過JSON複製有一定的侷限性,對象中的值value的數據類型爲undefined、function和symbol時直接被忽略。
var obj = {
a:1,
b:[1,2,3],
c:undefined,
d:function (){
console.log(1);
},
e:Symbol()
}
var obj2 = JSON.parse(JSON.stringify(obj));
console.log(obj,obj2);
二、遞歸實現深拷貝
面試題:深拷貝如何實現?
// 定義判斷數據類型的函數
function getClass(obj){
return Object.prototype.toString.call(obj).slice(8,-1);
}
function deepCopy(obj){
var result,
oclass = getClass(obj);
// 判斷傳入obj是否是引用類型
if(oclass == 'Object') result = {};
else if(oclass == 'Array') result = [];
else return obj;
// 遍歷對象
for(let key in obj){
var copy = obj[key];
if(getClass(copy) == 'Object'||getClass(copy) == 'Array'){
result[key] = deepCopy(copy); // 再次調用函數
// result[key] = arguments.callee(copy);
} else {
result[key] = copy;
}
}
return result;
}
var obj = {
a:1,
b:[1,2,3],
c:undefined,
d:function (){
console.log(1);
},
e:Symbol()
}
var obj2 = deepCopy(obj);
obj.a = 10;
obj.b[0] = 4;
console.log(obj,obj2);
三、通過使用第三方工具庫–jQuery
var obj = {
a:1,
b:[1,2,3],
c:undefined,
d:function (){
console.log(1);
},
e:Symbol()
}
var obj2 = $.extend(true,{},obj);
// jQuery.extend([deep],target,object1[,objectN])
// true設置爲深拷貝,false是默認值爲淺拷貝
obj.a = 10;
obj.b[0] = 4;
console.log(obj,obj2);
四、通過第三方工具庫–lodash
使用_.cloneDeep(value)函數,它會遞歸拷貝value(深拷貝)
var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects); // 返回拷貝後的值
console.log(deep[0] === objects[0]);
// => false
五、使用immutable.js-----性能最高
六、通過Object.create()/Object.assign()–淺拷貝
Object.create()方法創建一個新對象,使用現有的對象來提供新創建的對象的__proto__。
Object.assign()方法用於將所有可枚舉屬性的值從一個或多個源對象複製到目標對象。它將返回目標對象。
var obj = {
a: 1,
b: [1, 2, 3],
c: undefined,
d: function () {
console.log(1);
},
e: Symbol()
}
var obj2 = Object.create(obj); // 使用繼承的方式
// 同理,使用Object.assign()
var obj3 = {};
Object.assign(obj3, obj);
obj.a = 10;
obj.b[0] = 4;
console.log(obj, obj2, obj3);
但是這兩種方法都只對一層的對象有效