javaScript終極版-深拷貝
阿新 • • 發佈:2020-11-30
-------------人工分割線-------------
淺拷貝這裡不做介紹了,深拷貝的實現要點,除了一定要深!還要能相容各種型別,如函式,正則、Date等等。
其實日常業務開發中,Json.parse(Json.stringfy(obj))已經能夠解決90%左右的克隆需求。還有Object.assign() Object.create()都能滿足一定的克隆需求。
但上班擰螺絲,面試造航母的精神不容小覷!本著專研精神去看待怎麼才能寫個牛逼、各種場合都能通用的克隆方式?我做了不少功課。
在思考如何實現深拷貝之前,首先得弄明白:
實現思路:
- 使用遞迴實現巢狀物件的遍歷
- 增加WeakMap來快取已經建立的克隆物件解決迴圈引用問題
- 區分不同資料型別的處理方式,增加通用型別集合來儲存通用型別,方便日後拓展
直接上程式碼:
待克隆物件
let obj = { newDate: new Date('2020-10-11 12:00:01'), null: null, string: 'string', num: 23, nan: NaN, func: function () {console.log('function')}, arr: [1,2,3], reg: /ABC\-001/, regObj: new RegExp(/ABC/), object: { c: { a: 1 } }, }; obj.loop = obj; // 迴圈引用 let sup = { name: 'super', show: function () { console.log('show') } } let objectSup = { objectSupName: 'objectSupName', objectSupShow: function () { console.log('objectSupShow') } } Object.setPrototypeOf(obj, sup); // 根物件設定原型物件 Object.setPrototypeOf(obj.object, objectSup); // 子物件設定原型物件
核心程式碼
// 使用WeakMap是便於回收 function deepClone(obj, cacheCurr = new WeakMap()) { // 如果該物件已經建立好,則從快取中獲取直接返回 if (cacheCurr.has(obj)) return cacheCurr.get(obj); // 通用的型別集合,方便後面統一處理:new obj.constructor(obj),所以該集合一定是要能夠這樣建立的才能放進來 const types = ['RegExp', 'Date', 'Set', 'Map', 'WeakMap', 'WeakSet']; // 獲取當前物件型別 let objDataType = Object.prototype.toString.call(obj).slice(8, -1); // 對比當前型別是否在通用型別中,在則統一處理克隆。【較通用的處理方式】 if(types.includes(objDataType)) return new obj.constructor(obj); // 建立克隆物件 let cloneObj = objDataType === 'Array' ? [] : {}; // 繼承原型 if(obj) Object.setPrototypeOf(cloneObj,Object.getPrototypeOf(obj)); // 普通引用型別及非引用型別克隆,Reflect.ownKeys能夠獲取自身所有屬性【非列舉也可】 for(let key of Reflect.ownKeys(obj)) { let value = obj[key]; let valueType = Object.prototype.toString.call(value).slice(8, -1); // 引用型別處理 if(valueType === 'Object' || valueType === 'Array' || types.includes(valueType)) { // 對引用型別進行遞迴進入當前級的下一級進行遍歷 cloneObj[key] = deepClone(value, cacheCurr); // 記錄已建立引用 cacheCurr.set(obj, cloneObj); } else { // 非引用型別處理 cloneObj[key] = value; } } return cloneObj; }
程式碼註釋感覺都寫的很清楚了。寫完這篇文章就可以安心的來一把無限火力了。
測試過挺多資料結構的都完美通過。如果有發現問題的同學幫忙指出來。感激不盡