一文徹底解讀前端深淺拷貝的理解和幾種使用方法
前言
深拷貝和淺拷貝是面試中經(jīng)常被問到了,理解其原理和深淺拷貝差異以及多種深淺拷貝方法才能熟練在實際項目中使用做到游刃有余。本文將從作用原理到具體代碼實現(xiàn)和多種使用方法進行展開解讀。
深淺拷貝的理解
淺拷貝
淺拷貝從字面意義上就是淺層的拷貝對象,不涉及到深層次的拷貝,也就是說只復(fù)制對象表層數(shù)據(jù),只是為原來的對象創(chuàng)建新的內(nèi)存,但是嵌套的引用類型(如:數(shù)組、子對象)仍然需要與原對象共享內(nèi)存,修改副本的嵌套字段會同步影響原對象,進而產(chǎn)生污染。
其核心就是,由于JS的數(shù)據(jù)類型的存儲機制,基本類型(字符串、數(shù)字等)直接存在棧內(nèi)存中,復(fù)雜類型(對象、數(shù)組等)在棧中只存堆內(nèi)存的地址引用,而堆內(nèi)存才存實際的數(shù)據(jù)。淺拷貝時,只是復(fù)制棧內(nèi)存而不對堆內(nèi)存進行復(fù)制。 如圖:

極簡代碼理解就是:
// 原始對象
const userInfo = {
name: "張三", // 基本類型(直接存在棧內(nèi)存里)
address: { city: "北京" } // 復(fù)雜數(shù)據(jù)類型(地址引用在棧,實際數(shù)據(jù)在堆)
};
// 淺拷貝:創(chuàng)建新對象
const formData = { ...userInfo };
// 1. 對比新對象本身的地址
console.log(userInfo === formData); // false,說明地址不同,是新的內(nèi)存
// 2. 對比嵌套address的地址
console.log(userInfo.address === formData.address); // true,相同,說明內(nèi)存共享,指向的是同一個地址
// 3. 修改嵌套字段,驗證污染
formData.address.city = "上海";
console.log(userInfo.address.city); // 輸出"上海",說明原對象被污染了
深拷貝
理解了淺拷貝,深拷貝就是完全復(fù)制原始對象及所有的嵌套數(shù)據(jù),會為原對象和所有嵌套的引用類型(如數(shù)組、子對象)創(chuàng)建獨立的內(nèi)存空間,副本與原對象徹底隔離,修改副本不會影響到原對象。
深淺拷貝的方法
淺拷貝的5種常用方法
1. 對象展開運算符{...obj},最簡潔的實現(xiàn)方式,適用于普通對象
const shallowCopy = { ...userInfo };
2.數(shù)組展開運算符,數(shù)組專屬淺拷貝
const shallowCopy = { ...originArr };
3.Object.assign(target,source),可以合并多個對象,僅淺拷貝源對象表層
const shallowCopy = Object.assign({},userInfo1,userInfo2,userInfo3,....);
4.數(shù)組slice(),數(shù)組截?。ú粋鲄r等價于淺拷貝)
const shallowCopy = originalArr.slice();
5.數(shù)組concat(),拼接空數(shù)組實現(xiàn)淺拷貝
const shallowArr = originalArr.concat([]);
深拷貝的4種常用方法
1.JSON.parse(JSON.stringify(obj)),最常用(局限性:不支持函數(shù)、Symbol、Date、RegExp)
const deepCopy = JSON.parse(JSON.stringify(userInfo));
2.遞歸遍歷拷貝, 自定義實現(xiàn)(靈活處理所有類型,需手寫邏輯),面試手寫題???/p>
function deepClone(obj){
// 類型判斷
if(obj isntanceof Date) return new Date(obj);
if(obj instanceof RegExp) return new RegExp(obj);
if(obj instanceof Error) return new Error(obj.message);
if(obj instanceof Function) return function(...args){
return obj.call(this,...args);
};
if( obj === null || typeof obj !== 'object') return obj;
const newObj = Array.isArray(obj) ? [] : {};
for(let key in obj){
if(Object.hasOwn(obj,key)){
if(typeof obj[key] === "object"){
newObj[key] = deepClone(obj[key]); // 遞歸拷貝嵌套層
}
else{
newObj[key] = obj[key]
}
}
}
return newObj;
}
3.第三方庫, 穩(wěn)定可靠(開發(fā)首選)
- Lodash中的
_.cloneDeep(obj)(支持所有類型,處理循環(huán)引用) - jQuery中的
$.extend(true,{},obj)(第一個參數(shù)為true表示深拷貝)
4.structuredClone(), 瀏覽器原生API,支持循環(huán)引用、Date/RegExp,但不支持函數(shù)
總結(jié)
到此這篇關(guān)于前端深淺拷貝的理解和幾種使用方法的文章就介紹到這了,更多相關(guān)深淺拷貝理解和使用方法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript貪吃蛇游戲設(shè)計與實現(xiàn)
這篇文章主要為大家詳細介紹了javascript貪吃蛇游戲設(shè)計與實現(xiàn),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-09-09

