對於深拷貝,淺拷貝的概念不多說,概念可以自行百度喲!這裏對深拷貝對象進行一些研究!
只有值類型數據的深拷貝
針對只有值的數據對象,下面一行代碼足以!
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對象等等的坑?