對於深拷貝,淺拷貝的概念不多說,概念可以自行百度喲!這裡對深拷貝物件進行一些研究!
只有值型別資料的深拷貝
針對只有值的資料物件,下面一行程式碼足以!
JSON.parse(JSON.stringify(obj))
不嚴謹的簡單的深拷貝
function clone(source) {
var target = {};
for(var i in source) {
if (source.hasOwnProperty(i)) {
if (typeof source[i] === `object`) {
target[i] = clone(source[i]); // 注意這裡
} else {
target[i] = source[i];
}
}
}
return target;
}
問題存在:
- 沒有對引數做檢驗
- 判斷是否物件的邏輯不夠嚴謹
- 沒有考慮陣列的相容
進階深拷貝
function isObj(obj)
{
return (typeof obj === `object` || typeof obj === `function`) && obj !== null
}
function deepCopy(obj)
{
let tempObj = Array.isArray(obj) ? [] :{};
for(let key in obj)
{
tempObj[key] = isObj(obj[key]) ? deepCopy(obj[key]) : obj[key];
}
return tempObj;
}
問題存在:
- 拷貝環,也就是對 物件迴圈引用 的拷貝出現問題
針對環的深拷貝
可以使用一個WeakMap結構儲存已經被拷貝的物件,每一次進行拷貝的時候就先向WeakMap查詢該物件是否已經被拷貝,如果已經被拷貝則取出該物件並返回,將deepCopy函式改造成如下:
function isObj(obj)
{
return (typeof obj === `object` || typeof obj === `function`) && obj !== null
}
function deepCopy(obj, hash = new WeakMap()) {
if(hash.has(obj)) return hash.get(obj)
let cloneObj = Array.isArray(obj) ? [] : {}
hash.set(obj, cloneObj)
for (let key in obj) {
cloneObj[key] = isObj(obj[key]) ? deepCopy(obj[key], hash) : obj[key];
}
return cloneObj
}
問題存在:
- 沒有考慮對new Date(),正則,函式型別的物件的拷貝
結合環,針對date,reg,箭頭函式型別的深拷貝
const obj = { arr: [111, 222], obj: {key: `物件`}, a: () => {console.log(`函式`)}, date: new Date(), reg: /正則/ig}
function isObj(obj)
{
return (typeof obj === `object` || typeof obj === `function`) && obj !== null
}
function deepCopy(obj, hash = new WeakMap()) {
let cloneObj;
let Constructor = obj.constructor;
switch(Constructor){
case RegExp:
cloneObj = new Constructor(obj)
break;
case Date:
cloneObj = new Constructor(obj.getTime())
break;
case Function:
cloneObj = eval(obj.toString());
break;
default:
if(hash.has(obj)) return hash.get(obj)
cloneObj = new Constructor()
hash.set(obj, cloneObj)
}
for (let key in obj) {
cloneObj[key] = isObj(obj[key]) ? deepCopy(obj[key], hash) : obj[key];
}
return cloneObj;
}
const cloneObj = deepCopy(obj);
console.log(cloneObj);
更多遺留問題,針對函式進行拷貝,若是function,非箭頭函式,如何解決?還有,若要拷貝原型鏈上的屬性?如何拷貝不可列舉屬性? 如何拷貝Error物件等等的坑?