一、什麼是深拷貝
在javascript中,簡單數據類型的賦值是直接傳遞值,而複雜數據類型則是傳遞地址。而深拷貝就是指在拷貝時會開闢新的內存地址存放數據,而不是對原地址直接引用。
舉個例子,如果我們只是將一個對象賦值給另一個變量,那麼這兩個變量指向的是同一個地址,修改其中一個對象會影響到另一個對象,這就是淺拷貝:
var obj1 = {a: 1, b: 2};
var obj2 = obj1;
obj2.a = 3;
console.log(obj1.a); // 3
而如果我們進行深拷貝,如下所示:
var obj1 = {a: 1, b: 2};
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.a = 3;
console.log(obj1.a); // 1
這個時候,對象obj1的屬性a並沒有受到影響。
二、深拷貝的實現方式
1、遞歸實現深拷貝
深拷貝的實現方式有很多,其中一種比較常用的方式就是遞歸。
function clone(target){
let result;
if(typeof target === 'object'){
if(Array.isArray(target)){
result = [];
for(let i in target){
result.push(clone(target[i]));
}
}else if(target === null){
result = null;
}else if(target.constructor === RegExp){
result = target;
}else{
result = {};
for(let i in target){
result[i] = clone(target[i]);
}
}
}else{
result = target;
}
return result;
}
遞歸的方式就是遍歷對象和數組,每一層都新建一個相同的對象或數組,如果遇到還是對象或數組就再次調用函數進行遍歷。
但是該方法有一些缺點,會遇到一些環引用的情況(即對象中包含自己或循環引用),就會導致函數會陷入死循環,從而導致瀏覽器卡死。
2、使用JSON解析實現深拷貝
在JavaScript中,我們還可以通過JSON對象的解析方法進行深拷貝,如下所示:
var obj1 = {a: 1, b: {c: 2}};
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.b.c = 5;
console.log(obj1.b.c); // 2
通過JSON.parse(JSON.stringify())可以實現一個簡單的深拷貝,但是該方法也有一些缺點:
- 該方法只適用於JSON格式可轉的數據類型,對於一些不能轉成JSON格式的數據類型如:function、Date等就不能實現深拷貝。
- 對於包含循環引用的對象或數據也無法正常解析,會進入死循環。
- 拷貝對象類型時,對象里的function、undefined等會被忽略。
3、使用第三方庫進行深拷貝
除了手動實現深拷貝外,也可以使用一些第三方庫來進行深拷貝,如lodash、jQuery等。
//使用lodash的cloneDeep()方法進行深拷貝
var obj1 = {a: 1, b: {c: 2}};
var obj2 = _.cloneDeep(obj1);
obj2.b.c = 5;
console.log(obj1.b.c); // 2
通過第三方庫的方法進行深拷貝是最簡單,最安全的方式。
三、深拷貝的使用方法
深拷貝在實際開發中也非常常用,在以下幾個場景中使用:
- 在實現對象繼承時,我們需要對父類對象進行深拷貝以保留其所有屬性和方法。
- 在操作複雜的嵌套結構數據時,深拷貝能夠保證不會影響到原數據。
- 當需要對某個對象或數組進行拷貝,而這個數據又需要改動時,可以使用深拷貝生成一個全新的數據,從而不影響原數據。
//深拷貝操作示例
var obj1 = {a: 1, b: {c: 2}};
var obj2 = _.cloneDeep(obj1);
obj2.b.c = 5;
console.log(obj1.b.c); // 2
console.log(obj2.b.c); // 5
四、深拷貝的優化
我們在使用深拷貝時需要注意,由於深拷貝的過程比較耗費內存資源,我們需要儘可能地減少深拷貝的次數。
比如,如果我們在Vue或React框架中需要對一個對象的某個值進行修改,我們可以直接替換改變對象的指向,而不是對整個對象進行深拷貝,從而提高程序的運行效率。
//Vue組件中示例
data(){
return {
obj: {
a: 1,
b: 2,
c: [3, 4, 5]
}
}
},
methods: {
changeValue(val){
this.obj.b = val;
}
}
在示例中,如果我們需要更改obj對象的b值,我們可以使用this.obj.b = val;的方式直接進行修改,不需要進行深拷貝。
五、總結
本文重點講解了深拷貝的背景和實現方式,並給出了實際應用的場景和優化方法。在實際工作中,我們需要根據業務需求選擇合適的深拷貝方式,避免出現不必要的問題。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/247462.html