煙臺h5網(wǎng)站制作sem優(yōu)化和seo的區(qū)別
在前端開發(fā)中,深克隆(Deep Clone)和淺克隆(Shallow Clone)是常見的操作。淺克隆和深克隆的區(qū)別主要體現(xiàn)在對象內(nèi)部嵌套對象的處理方式上。
1. 淺克隆(Shallow Clone)
淺克隆是指創(chuàng)建一個新對象,但對于原對象中嵌套的對象,淺克隆只復制它們的引用,而不是創(chuàng)建新的對象。換句話說,淺克隆只是“淺復制”了對象的屬性,嵌套的對象還是共享相同的引用。
🌰:
// 淺克隆
const shallowClone = (obj) => {return { ...obj };
};// 或者使用 Object.assign
const shallowClone2 = (obj) => {return Object.assign({}, obj);
};const obj1 = { name: 'John', address: { city: 'NY' } };
const obj2 = shallowClone(obj1);obj2.address.city = 'LA';console.log(obj1.address.city); // 輸出 'LA'
console.log(obj2.address.city); // 輸出 'LA'
2. 深克隆(Deep Clone)
深克隆是指創(chuàng)建一個新對象,并且遞歸地復制原對象中的所有屬性,包括嵌套的對象(嵌套對象也會被克隆為新的對象)。這樣,修改新對象不會影響到原對象,反之亦然。
1. 遞歸實現(xiàn)
// 深克隆實現(xiàn)(遞歸)
const deepClone = (obj) => {if (obj === null || typeof obj !== 'object') return obj;const newObj = Array.isArray(obj) ? [] : {}; // 判斷是數(shù)組還是對象for (let key in obj) {if (obj.hasOwnProperty(key)) {newObj[key] = deepClone(obj[key]); // 遞歸克隆}}return newObj;
};
const obj1 = { name: 'John', address: { city: 'NY' }, hobbies: ['reading', 'gaming'] };
const obj2 = deepClone(obj1);
obj2.address.city = 'LA';
obj2.hobbies[0] = 'traveling';
console.log(obj1.address.city); // 輸出 'NY'
console.log(obj2.address.city); // 輸出 'LA'
console.log(obj1.hobbies[0]); // 輸出 'reading'
console.log(obj2.hobbies[0]); // 輸出 'traveling'
2. JSON 方法?
JSON.parse(JSON.stringify(...)) :是前端開發(fā)中常用的一種快速實現(xiàn)深克隆的方法,但它也有一些缺陷。
const deepCloneUsingJSON = (obj) => {return JSON.parse(JSON.stringify(obj));
};const obj1 = { name: 'John', address: { city: 'NY' }, hobbies: ['reading', 'gaming'] };
const obj2 = deepCloneUsingJSON(obj1);obj2.address.city = 'LA';
obj2.hobbies[0] = 'traveling';console.log(obj1.address.city); // 輸出 'NY'
console.log(obj2.address.city); // 輸出 'LA'
console.log(obj1.hobbies[0]); // 輸出 'reading'
console.log(obj2.hobbies[0]); // 輸出 'traveling'
3. JSON.stringify 的缺陷?
盡管其是一種快速且簡單的深克隆方法,但它也有幾個明顯的缺陷:
1、無法克隆函數(shù):JSON 序列化過程會丟失對象中的函數(shù)。例如:
const obj1 = { name: 'John', greet: () => console.log('Hello') };
const obj2 = JSON.parse(JSON.stringify(obj1));
console.log(obj2); // { name: 'John' }
obj2.greet(); // 報錯:obj2.greet is not a function
2、無法處理 undefined:對象中的 undefined 值會被丟失,并且會在序列化過程中變成 null。
const obj1 = { value: undefined };
const obj2 = JSON.parse(JSON.stringify(obj1));console.log(obj2.value); // 輸出: undefined
3、無法處理特殊對象:某些 JavaScript 特殊對象(如 Date、RegExp、Map、Set、Promise 等)無法正確克隆,變成普通的對象或丟失其原有屬性。
const obj1 = { date: new Date(), map: new Map() };
const obj2 = JSON.parse(JSON.stringify(obj1));console.log(obj2); // { date: '2025-01-08T06:39:12.842Z', map: {} }
console.log(obj2.date instanceof Date); // 輸出: false
console.log(obj2.map instanceof Map); // 輸出: false
4、循環(huán)引用無法處理:如果對象包含循環(huán)引用(即一個對象的屬性引用了它自身),JSON.stringify 會拋出錯誤。
const obj1 = {};
obj1.self = obj1;const obj2 = JSON.parse(JSON.stringify(obj1));
// 報錯:TypeError: Converting circular structure to JSON 無法轉(zhuǎn)換遞歸結(jié)構(gòu)
4. 深度克隆的缺陷和完善
在實際開發(fā)中,基于?JSON.stringify 的深克隆方法需要處理一下。
1、處理 undefined 和 null:在序列化之前,進行預處理,避免 undefined 變成 null,或者在反序列化時進行特殊處理。
2、處理循環(huán)引用:為防止循環(huán)引用導致的錯誤,可以使用 WeakMap?來存儲已訪問的對象,并在遇到已訪問的對象時直接返回,避免無限遞歸。
3、支持 Date、RegExp 等特殊對象:在克隆過程中判斷對象的類型,使用 Object.prototype.toString.call() 來判斷,進行相應的處理。
5. 更健壯的深克隆代碼
// 考慮循環(huán)引用
const cache = new WeakMap(); // 確保對象在外層銷毀時,Map結(jié)構(gòu)自動銷毀,防止內(nèi)存泄露
const deepClone = (obj) => {if (obj === null || typeof obj !== 'object') return obj;// obj是對象if (cache.has(obj)) {return cache.get(obj);}const newObj = Array.isArray(obj) ? [] : {}; // 判斷是數(shù)組還是對象cache.set(obj, newObj);// 考慮原型if (Object.getPrototypeOf(obj) !== Object.prototype) {// newObj.__proto__ = Object.getPrototypeOf(obj);// orObject.setPrototypeOf(newObj, Object.getPrototypeOf(obj));}for (let key in obj) {// 考慮繼承屬性if (obj.hasOwnProperty(key)) {newObj[key] = deepClone(obj[key]); // 遞歸克隆}}return newObj;
};
class Person {constructor(name, age) {this.name = name;this.age = age;}eat() {console.log('eat');}
}
Person.prototype.hobby = 'game';
Person.prototype.say = function () {console.log('say');
};
const obj = new Person('張三', 18);
// 循環(huán)引用
obj.h = obj;
console.log(obj);
console.log(deepClone(obj)); // <ref *1> Person { name: '張三', age: 18, h: [Circular *1] }
總結(jié)
1、淺克隆:只復制對象的第一層,嵌套對象還是共享引用。
2、深克隆:遞歸復制整個對象,包括嵌套對象。