JavaScript深拷貝踩坑小記
阿新 • • 發佈:2019-01-06
一、關於深拷貝
關於深拷貝與淺拷貝的理解,這裡不過多的進行描述。因為此前自己總結了一次深拷貝的常見方法,JSON.parse(JSON.stringify(obj)),jQury的$.extend(true,{},obj),for...in加遞迴
已經滿足了大部分的業務需求。具體內容可見JavaScript之深拷貝和淺拷貝
二、然而,有坑!
const data = { arr: ["test0", "test1"], obj: { title: '標題', dataIndex: "name" }, onClick: () => { console.log('this is a function') }, date: new Date(), } const deepCopy = function (obj) { var str, newobj = obj.constructor === Array ? [] : {}; if (typeof obj !== 'object') { return; } else if (window.JSON) { str = JSON.stringify(obj), //json物件轉字串,系列化 newobj = JSON.parse(str); //還原為json物件 } else { for (var i in obj) { newobj[i] = typeof obj[i] === 'object' ? deepCopy(obj[i]) : obj[i]; } } return newobj; }; const result1 = JSON.parse(JSON.stringify(data)); const result2 = deepCopy(data); console.log('------------------------------------'); console.log(result1); console.log('------------------------------------'); console.log('------------------------------------'); console.log(result2); console.log('------------------------------------');
由以下輸出結果,可以看出,這兩個方法無法拷貝含有function,date屬性的物件!!!
三、解決方案
1. 結構化克隆演算法
//需要進一步完善處理對待各種型別; const deepCopy = (obj, hash = new WeakMap()) => { let cloneObj let Constructor = obj.constructor switch (Constructor) { case Object: cloneObj = new Constructor(obj) break case RegExp: cloneObj = new Constructor(obj) break case Date: cloneObj = new Constructor(obj.getTime()) break default: if (hash.has(obj)) return hash.get(obj) cloneObj = new Constructor() hash.set(obj, cloneObj) } for (let key in obj) { cloneObj[key] = obj[key].constructor === constructor ? deepCopy(obj[key], hash) : obj[key]; } return cloneObj } const result3 = deepCopy(data); console.log('------------------------------------'); console.log(result3); console.log('------------------------------------');
參考MDN上的結構化克隆演算法,下圖為輸出結果,達到預期效果:
2. lodash中的_.cloneDeep() 方法
目前是我覺得最直接,最完整的解決方案,畢竟可以一句話解決問題,絕不多說一句(其實我就是懶)。