1.如何實現深拷貝?
1.簡單粗暴使用JSON.parse(JSON.stringify(obj))
- 存在的問題:不支持函數和正則等拷貝。
let obj = {
name: 'ha',
friends: {
name: 'zj',
parent: {
name: 'parent'
}
},
score: [ 1, 2, 3 ],
getName: function () {
return this.name;
},
reg: /\w/g
}
const obj_2 = JSON.parse(JSON.stringify(obj));
obj_2.friends.parent.name = 12121212;
obj_2.score.push('ja');
console.log('obj_2==', obj_2);
console.log('obj==', obj);
結果如下:
2.循環遞歸
- 我自己的遞歸實現
// 自己實現一個對象的深拷貝
function deepClone(sourceObj) {
if (typeof sourceObj !== 'object' || sourceObj === null) return sourceObj;
const cloneObj = {}
for (let key in sourceObj) { // for...in 會遍歷對象自身的和繼承的可枚舉的屬性。
if (sourceObj.hasOwnProperty(key)) { // 只拷貝對象自身的屬性
if (typeof sourceObj[key] !== 'object'){ // 這裏分爲兩種:1.基本類型,2.函數(我覺得無法對函數進行深拷貝了)
cloneObj[key] = sourceObj[key];
} else { // 這裏分爲兩種:1.數組,2.對象 ,3.正則(正則這裏,我暫時不清楚如何深拷貝,哈哈)
!sourceObj[key].forEach ?
(Object.prototype.toString.call(sourceObj[key]) !== '[object RegExp]' ? cloneObj[key] = deepClone(sourceObj[key]) : cloneObj[key] = sourceObj[key]) :
cloneObj[key] = [...sourceObj[key]];
}
}
}
return cloneObj;
}
判斷一個引用類型的變量是數組,對象還是正則。用instanceof
或者Object.prototype.toString.call(obj)
。
用instanceof
判斷的具體代碼爲:
if (typeof obj === 'object') {
if (obj instanceof Array) {
// 爲數組
} else (obj instanceof RegExp) {
// 爲正則
} else {
// 爲對象
}
}
- 修言大佬的實現
function deepClone(obj) {
// 如果是 值類型 或 null,則直接return
if(typeof obj !== 'object' || obj === null) {
return obj
}
// 定義結果對象
let copy = {}
// 如果對象是數組,則定義結果數組
if(obj.constructor === Array) {
copy = []
}
// 遍歷對象的key
for(let key in obj) {
// 如果key是對象的自有屬性
if(obj.hasOwnProperty(key)) {
// 遞歸調用深拷貝方法
copy[key] = deepClone(obj[key])
}
}
return copy
}
- 存在的問題:
循環引用,即死循環,導致爆棧。
var obj = {
name: 'ha',
friends: {
name: 'zj',
parent: {
name: 'parent'
}
},
score: [ 1, 2, 3 ],
getName: function () {
return this.name;
}
}
obj.issue = obj;
調用deepClone(obj)後,出現如下結果。棧溢出
- 那麼如何解決呢?
思路:可以開闢一個數組,用來存儲已經拷貝的對象,然後,每次拷貝之前,進行判斷該對象是否已經拷貝過即可。
const hadDeepClone = []; // 存儲已經拷貝過的引用類型值
function deepClone(sourceObj) {
if (typeof sourceObj !== 'object') return sourceObj;
if (hadDeepClone.includes(sourceObj)) {
return;
} else{
hadDeepClone.push(sourceObj);
}
const cloneObj = {}
for (let key in sourceObj) { // for...in 會遍歷對象自身的和繼承的可枚舉的屬性。
if (sourceObj.hasOwnProperty(key)) { // 只拷貝對象自身的屬性
if (typeof sourceObj[key] !== 'object'){ // 這裏分爲兩種:1.基本類型,2.函數(我覺得無法對函數進行深拷貝了)
cloneObj[key] = sourceObj[key];
} else { // 這裏分爲兩種:1.數組,2.對象 ,3.正則(正則這裏,我暫時不清楚如何深拷貝,哈哈)
!sourceObj[key].forEach ?
(Object.prototype.toString.call(sourceObj[key]) !== '[object RegExp]' ? cloneObj[key] = deepClone(sourceObj[key]) : cloneObj[key] = sourceObj[key]) :
cloneObj[key] = [...sourceObj[key]];
}
}
}
return cloneObj;
}
結果如下: