返回
前端面试100道手写题(4)—— 深浅拷贝
前端
2024-01-31 20:11:02
前言
深浅拷贝是前端面试中经常被问到的经典题目。它不仅仅考察的是实现逻辑,更是对整个Javascript语言背后的理论知识的考察,包括基础数据类型、原型链等等。下面,我们就从简单到困难,一步步实现深浅拷贝。
1. 基础数据类型的深浅拷贝
对于基础数据类型(如数字、字符串、布尔值),深浅拷贝和浅拷贝是没有区别的。因为基础数据类型在内存中存储的是实际值,而不是引用。因此,无论使用哪种拷贝方式,都会得到一个新的值。
// 基础数据类型的深拷贝
const num1 = 1;
const num2 = num1;
num2 += 1;
console.log(num1); // 1
// 基础数据类型的浅拷贝
const str1 = 'hello';
const str2 = str1;
str2 += 'world';
console.log(str1); // hello
2. 引用数据类型的浅拷贝
对于引用数据类型(如对象、数组),浅拷贝只拷贝引用,不会拷贝实际值。因此,如果修改浅拷贝后的对象或数组,原始对象或数组也会受到影响。
// 引用数据类型的浅拷贝
const obj1 = { name: '张三' };
const obj2 = obj1;
obj2.name = '李四';
console.log(obj1); // { name: '李四' }
3. 引用数据类型的深拷贝
为了实现引用数据类型的深拷贝,需要遍历对象或数组的每一个属性,并为每个属性创建一个新的副本。
// 引用数据类型的深拷贝
function deepCopy(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
if (Array.isArray(obj)) {
const newArr = [];
for (const item of obj) {
newArr.push(deepCopy(item));
}
return newArr;
}
const newObj = {};
for (const key in obj) {
newObj[key] = deepCopy(obj[key]);
}
return newObj;
}
const obj1 = { name: '张三', age: 20 };
const obj2 = deepCopy(obj1);
obj2.name = '李四';
console.log(obj1); // { name: '张三', age: 20 }
4. 使用JSON实现深拷贝
JSON.parse()和JSON.stringify()可以实现引用数据类型的深拷贝。JSON.stringify()将对象或数组转换成JSON字符串,JSON.parse()将JSON字符串转换成对象或数组。
// 使用JSON实现深拷贝
const obj1 = { name: '张三', age: 20 };
const obj2 = JSON.parse(JSON.stringify(obj1));
obj2.name = '李四';
console.log(obj1); // { name: '张三', age: 20 }
5. 考虑循环引用的深拷贝
在某些情况下,对象或数组中可能存在循环引用。如果直接使用深拷贝算法,可能会陷入死循环。为了解决这个问题,可以在深拷贝算法中使用一个Map来记录已经拷贝过的对象或数组,如果遇到循环引用,则直接返回Map中对应的对象或数组。
// 考虑循环引用的深拷贝
function deepCopyWithCycle(obj, map = new Map()) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
if (map.has(obj)) {
return map.get(obj);
}
if (Array.isArray(obj)) {
const newArr = [];
for (const item of obj) {
newArr.push(deepCopyWithCycle(item, map));
}
map.set(obj, newArr);
return newArr;
}
const newObj = {};
for (const key in obj) {
newObj[key] = deepCopyWithCycle(obj[key], map);
}
map.set(obj, newObj);
return newObj;
}
const obj1 = { name: '张三', age: 20 };
obj1.friend = obj1;
const obj2 = deepCopyWithCycle(obj1);
obj2.name = '李四';
console.log(obj1); // { name: '张三', age: 20, friend: { name: '李四', age: 20, friend: ... } }
总结
深浅拷贝是前端面试中常见的题目,也是对Javascript语言背后的理论知识的考察。通过对基础数据类型和引用数据类型的深浅拷贝实现的讲解,我们可以深入理解Javascript语言的底层机制和原型链的概念。在实际开发中,根据不同的场景选择合适的拷贝方式,可以避免很多潜在的bug。