在撰寫 JS 的時候我們很常會對物件去進行深拷貝的處理,我們常見的深拷貝有三種做法,除了常見的做法以外,我還會額外介紹一個全新處裡深拷貝的方法。
關於淺拷貝跟深拷貝網路上已經有許多介紹文章了,這邊暫時不多做贅述!
const obj2 = JSON.parse(JSON.stringify(obj1));
這是最簡單的深拷貝方法,但所有非JSON支持的類型都將被忽略或轉換,日期會被轉換為字串,正規表達式會被丟棄。但是它的整體效能快,非常適合使用在小型且簡單的物件身上。
使用lodash
的cloneDeep
身為前端開發中的老牌子,第三方資料處理的套件, lodash
可以說是耳熟能詳,它本身提供了許多方便的函式來幫我們處理跟資料有關的計算。
它提供了cloneDeep
函數,能夠更全面的深拷貝各種資料類型。
import _ from 'lodash';
const newObj = _.cloneDeep(obj1);
function deepCopy(obj, hash = new WeakMap()) {
if (obj === null) return null;
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
if (typeof obj !== 'object') return obj;
if (hash.has(obj)) return hash.get(obj);
const cloneObj = new obj.constructor();
hash.set(obj, cloneObj);
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
cloneObj[key] = deepCopy(obj[key], hash);
}
}
return cloneObj;
}
const obj1 = {
name: 'mike',
info: {
age: 12,
address: 'taiwan',
sex: 'boy',
interest: {
code: 'javascript',
sports: 'basketball',
watch: 'movie',
},
},
};
const obj2 = deepCopy(obj1);
obj2.info.interest.code = "php";
console.log(obj1.info.interest);
console.log(obj2.info.interest);
可以通過遞迴的方式來實現深拷貝,這給了我們在開發上面的靈活性,不過這種方式在開發的管理上面就顯得有點笨重。接下來我要介紹第四種方法,也是重頭戲
JSON.parse(JSON.stringify(obj))
來做深拷貝,但這個方法有很多問題。它不能複製函數、忽略undefined
,也不能處理循環參考。而structuredClone
就像是一個升級版,它能搞定這些情況,而且使用起來超級簡單。const obj2 = structuredClone(obj1);
就這樣,二者完全獨立,互不影響,它真的很方便,尤其是在處理那些複雜的物件時。
但 structuredClone 也不是完美的,它也有一些限制
structuredClone
不能複製函數。structuredClone
支持許多內建的JavaScript type,但它並不支持複製某些特殊類型的物件,比如 Error
、Function
等。structuredClone
,但在一些舊版本的瀏覽器中可能不支援。如果你的網站支援較舊瀏覽器,可能需要考慮其他替代方案。Map
、Set
、ArrayBuffer
、DataView
等,structuredClone
會進行深拷貝,但它的行為可能與一些自定義的深拷貝函數有所不同。這邊附上 structuredClone 一些相關參考跟介紹,有興趣的朋友可以看一下,可以學到蠻多的。
Window:structuredClone() 方法