首先,我們需要實現壹個getter函數來判斷元素的類型。關於壹個元素的類型判斷,可以參考我另壹篇博文js中對Typeof和instanceof的詳細解釋。這裏我們用壹個更簡單的方法直接調用Object.prototype.toString方法。
函數getType(obj){
//tostring會返回不同標簽對應的構造函數。
var toString = object . prototype . toString;var map = { '[對象布爾值]':'布爾值',
[對象編號]':'編號',
[對象字符串]':'字符串',
[目標函數]':'函數',
[對象數組]':'數組',
[對象日期]':'日期',
[object RegExp]' : 'regExp ',
[對象未定義]':'未定義','[對象空值]':'空值',
[對象對象]':'對象'
};if(obj instance of Element){ return ' Element ';
}返回map[tostring . call(obj)];
}1234567891011121314151617181920
深層拷貝(深層克隆)
對於壹個引用類型,如果直接賦給另壹個變量,由於兩個引用指向同壹個地址,改變其中壹個引用會影響另壹個。當我們要復制壹個對象,切斷與它的聯系時,就需要使用深度復制。對於壹個對象,可能有多層結構,所以我們可以用遞歸來解決這個問題
函數deepClone(數據){
var type = getType(數據);var objif(type === 'array'){
obj =[];
} else if(type === 'object'){
obj = { };
} else {//不再有下壹級。
返回數據;
} if(type === 'array'){ for(var i = 0,len = data.length我& ltleni++){
obj . push(deep clone(data[I]);
}
} else if(type = = = ' object '){ for(var key in data){
obj[key]= deep clone(data[key]);
}
} return obj
}12345678910111213141516171819202122
對於函數類型,這裏是直接賦值,或者* * *享有壹個內存值。這是因為函數更多的是完成壹些功能,有壹個輸入值和壹個返回值,而對於上層業務來說,更多的是完成業務功能,並不需要真正的深度復制函數。
廣度優先遍歷
上面是用遞歸進行深度復制,顯然我們可以用樹的廣度優先遍歷來實現。
//這裏為了方便閱讀,只深入復制了對象。數組的判斷,參考上面的例子。
函數deepClone(數據){
var obj = { };var origin queue =[data];var copy queue =[obj];//下面兩個隊列用來保存復制時訪問的對象,避免對象環的問題(對象的壹個屬性值就是對象本身)。
var visit queue =[];var copy visit queue =[];while(origin queue . length & gt;0){ var _ data = origin queue . shift();var _ obj = copy queue . shift();
visit queue . push(_ data);
copy visit queue . push(_ obj);for(var key in _ data){ var _ value = _ data[key]if(type of _ value!== 'object'){
_ obj[key]= _ value;
} else {//使用indexOf可以發現數組中是否有相同的對象(indexOf實現的難點在於對象比較)。
var index = visit queue . index of(_ value);if(index & gt;= 0){
_ obj[key]= copy visit queue[index];
}
origin queue . push(_ value);
_ obj[key]= { };
copy queue . push(_ obj[key]);
}
}
} return obj
}12345678910111213141516171819202122232425262728293031
JSON
深層拷貝對象還有另壹種解決方案。當對象中沒有函數時,可以使用JSON解析和逆向解析得到深度復制對象。
閱讀全文