引用類型的深拷貝、淺拷貝在前端領域一直是個很重要的知識點,不只在業務中頻繁使用,也是面試官們喜歡考的的知識點之一。本篇將封裝引用類型的深拷貝、淺拷貝方法,並解決在封裝過程當中出現的問題。前端
1、淺拷貝面試
淺拷貝通常比較簡單,缺點也很明顯,引用類型的屬性並非真正的拷貝,而是拷貝的引用地址,改變一個當中的屬性值,另外一個也跟着變化。json
方法封裝:數組
/** * 淺拷貝 * @param {*} target * @returns */ export function clone (target) { if (target instanceof Array) { // return [...target] // return target.slice() // return [].concat(target) // return Array.from(target) // return target.filter(value => true) // return target.map(item => item) return target.reduce((pre, item) => { pre.push(item) return pre }, []) } else if (target!==null && typeof target==='object') { return {...target} } else {// 若是不是數組或對象, 直接返回 return target } }
爲了解決淺拷貝的痛點,因而就有了深拷貝,能夠拷貝引用類型的屬性,且互相獨立,互不影響。緩存
2、深拷貝(3種方法)函數
1.JSON.parse(JSON.stringify(obj)):JSON.stringify把對象轉成字符串,再用JSON.parse把字符串轉成新的對象spa
export function deepClone1 (target) { return JSON.parse(JSON.stringify(target)) }
這種深拷貝的方式我平時業務中也常常使用,但使用的前提是對拷貝的對象屬性很是清楚,屬性中不能包含函數,由於function沒辦法轉化爲json格式的對象,因此函數屬性會丟失!code
還有一個缺陷就是,若是拷貝的對象屬性中包含本身(循環引用),在深拷貝的時候會陷入死循環。對象
深拷貝後:blog
2.利用遞歸來進行深拷貝
export function deepClone2 (target) { // 被處理的目標是數組/對象 if (target instanceof Array || (target!==null && typeof target==='object')) { const cloneTarget = target instanceof Array ? [] : {} for (const key in target) { if (target.hasOwnProperty(key)) { cloneTarget[key] = deepClone2(target[key]) // 對屬性值進行遞歸處理 } } return cloneTarget } else { return target } }
打印結果1:解決函數屬性丟失
打印結果2:死循環問題沒有解決
3.利用「緩存池」來解決循環引用形成的死循環
export function deepClone3 (target, map=new Map()) { // 被處理的目標是數組/對象 if (target instanceof Array || (target!==null && typeof target==='object')) { // map中存在對應的克隆對象, 造成一個緩存池,若是當前對象存在,則返回 let cloneTarget = map.get(target) if (cloneTarget) { return cloneTarget // 不要對同一個對象進行屢次clone } // 建立克隆對象 if (target instanceof Array) { cloneTarget = [] // 保存到map容器 map.set(target, cloneTarget) // 向數組添加元素 target.forEach((item, index) => { cloneTarget[index] = deepClone(item, map) }) } else { cloneTarget = {} // 保存到map容器 map.set(target, cloneTarget) // 向對象添加屬性 for (const key in target) { if (target.hasOwnProperty(key)) { cloneTarget[key] = deepClone(target[key], map) // 對屬性值進行遞歸處理 } } } return cloneTarget } else { return target } }
打印結果:
利用緩存池來解決引用類型的循環引用問題,每一個引用類型只拷貝一次,這樣就不會陷入死循環了。
以上就是我對js中引用類型深拷貝和淺拷貝的理解和封裝了,若是你有更好的方案歡迎留言指教!
腳踏實地行,海闊天空飛