实现深浅拷贝
今天累了,写个简单的文章来凑个数吧,实现深浅拷贝,面试必备
实现深浅拷贝
浅拷贝
- Object.assign
- 扩展运算符
let obj2 = { ...obj1 }
- 自己简单实现
function isObj(obj) {
return typeof obj === 'object' && obj !== null;
}
// 遍历赋值
function clone(obj) {
if(!isOjb(obj)) {
return obj;
}
let res = Array.isArray(obj) ? [] : {};
for(let key in obj) {
if(Object.hasOwnProperty(key)) {
res[key] = obj[key];
}
}
return res;
}
深拷贝
- 通过JSON.stringify实现深拷贝,会有以下问题
- 值里面如果有undefined,函数,Symbol,通过stringify序列化后键值都会消失
- 无法解决循环引用
- 拷贝Date会变字符串,RegExp会变空值
- 无法拷贝不可枚举的属性
- 无法拷贝对象的原型链
- NaN,+ -Infinity变成null
自己实现深拷贝,步骤如下
- 先通过遍历对象的属性,实现浅拷贝
export function deepClone(obj) {
if (!isObject(obj)) {
return obj;
}
const result = {};
for(let key in obj) {
if (obj.hasOwnProperty(key)) {
result[key] = obj[key];
}
return result;
}
- 兼容数组
export function deepClone(obj) {
if (!isObject(obj)) {
return obj;
}
const result = Array.isArray(obj) ? [] : {};
for(let key in obj) {
if (obj.hasOwnProperty(key)) {
result[key] = obj[key];
}
}
return result;
}
- 加入递归实现深拷贝
export function deepClone(obj) {
if (!isObject(obj)) {
return obj;
}
const result = Array.isArray(obj) ? [] : {};
for(let key in obj) {
if (obj.hasOwnProperty(key)) {
if (isObject(obj[key])) {
//*
result[key] = deepClone(obj[key]);
//*
} else {
result[key] = obj[key];
}
}
}
return result;
}
- 解决循环引用问题(Map 或 WeakMap 或数组)
weakMap可能会有引用丢失的问题,可用Map和数组解决
export function deepClone(obj, weakMap = new WeakMap()) {
if (!isObject(obj)) {
return obj;
}
if(weakMap.has(obj)) {
return weakMap.get(obj);
}
const result = Array.isArray(obj) ? [] : {};
weakMap.set(obj, result);
for(let key in obj) {
if (obj.hasOwnProperty(key)) {
if (isObject(obj[key])) {
result[key] = deepClone(obj[key], weakMap);
} else {
result[key] = obj[key];
}
}
}
return result;
}
数组解决循环引用
function findArr(obj, arr) {
let res = null;
for(let item of arr) {
if(item.source === obj) {
res = item;
break
}
}
return res;
}
export function deepClone2(obj, saveArr = []) {
if(!isObject(obj)) {
return obj;
}
if(findArr(obj, saveArr)) {
return findArr(obj, saveArr).target;
}
const result = Array.isArray(obj) ? [] : {};
saveArr.push({
source: obj,
target: result
});
for(let key in obj) {
if(obj.hasOwnProperty(key)) {
if(isObject(obj[key])) {
result[key] = deepClone2(obj[key], saveArr);
}else {
result[key] = obj[key];
}
}
}
return result;
}
- 拷贝不可枚举的key和Symbol类型的key,Reflect.ownKeys列出所有的key,包括可枚举不可枚举和Symbol
export function deepClone(obj, weakMap = new WeakMap()) {
if (!isObject(obj)) {
return obj;
}
if(weakMap.has(obj)) {
return weakMap.get(obj);
}
const result = Array.isArray(obj) ? [] : {};
weakMap.set(obj, result);
Reflect.ownKeys(obj).forEach(key => {
if (obj.hasOwnProperty(key)) {
if (isObject(obj[key])) {
result[key] = deepClone(obj[key], weakMap);
} else {
result[key] = obj[key];
}
}
});
return result;
}
- 拷贝原型链
export function deepClone(obj, weakMap = new WeakMap()) {
if (!isObject(obj)) {
return obj;
}
if(weakMap.has(obj)) {
return weakMap.get(obj);
}
// const result = Array.isArray(obj) ? [] : {};
const descriptors = Object.getOwnPropertyDescriptors(obj)
const result = Object.create(Object.getPrototypeOf(obj), descriptors);
weakMap.set(obj, result);
Reflect.ownKeys(obj).forEach(key => {
if (obj.hasOwnProperty(key)) {
if (isObject(obj[key])) {
result[key] = deepClone(obj[key], weakMap);
} else {
result[key] = obj[key];
}
}
});
return result;
}
- 处理特殊对象
export function deepClone(obj, weakMap = new WeakMap()) {
if (!isObject(obj)) {
return obj;
}
if(weakMap.has(obj)) {
return weakMap.get(obj);
}
// 处理特殊对象 Boolean Number String Error均如此
if(obj.constructor === Date) {
return new Date(obj);
}
if(obj.constructor === RegExp) {
return new RegExp(obj);
}
// map set类似
if(obj.constructor === Map) {
let newTarget = new Map();
obj.forEach((value, key) => {
newTarget.set(key, value);
})
return newTarget;
}
/////////////
// const result = Array.isArray(obj) ? [] : {};
const descriptors = Object.getOwnPropertyDescriptors(obj)
const result = Object.create(Object.getPrototypeOf(obj), descriptors);
weakMap.set(obj, result);
Reflect.ownKeys(obj).forEach(key => {
if (obj.hasOwnProperty(key)) {
if (isObject(obj[key])) {
result[key] = deepClone(obj[key], weakMap);
} else {
result[key] = obj[key];
}
}
});
return result;
}
- 克隆函数(一般没有必要)
普通函数通过正则匹配, 箭头函数直接用eval(函数toString)
普通函数和箭头函数可通过有没有prototype来区分
function cloneFunc(func) {
// if(func.protytype) { // 普通函数
// // 前面是先行断言,后面是后行断言 仅当 ( 后面跟着一个或多个字符,且这一个或多个字符后面跟着 )中间可以多个空格{
// const paramReg = /(?<=\().+(?=\)\s+{)/;
// // 前面是先行断言,后面是后行断言 仅当 { 后面跟着一个或多个字符或换行,且这一个或多个字符后面跟着}
// const bodyReg = /(?<={)(.|\n)+(?=})/m; // m是多行搜索
// const funcString = func.toString();
// const param = paramReg.exec(funcString);
// const body = bodyReg.exec(funcString);
// if(body) {
// if(param) {
// const argList = param[0].split(',');
// return new Function(...arguments, body[0]);
// }else {
// return new Function(body[0]);
// }
// }else {
// return null;
// }
// } else { // 箭头函数
// return eval(func.toString());
// }
return eval(`(${func.toString()})`);
}
- 最后,如果不用递归来
export function deepClone3(obj) {
const stack = [];
const result = {};
stack.push({
parent: result,
key: undefined,
data: obj
});
while(stack.length) {
console.log('stack', stack);
let node = stack.pop();
let parent = node.parent;
let key = node.key;
let data = node.data;
let res = parent;
if(key !== undefined) {
res = parent[key] = {};
}
Reflect.ownKeys(data).forEach((key) => {
if(isObject(data[key])) {
stack.push({
parent: res,
key: key,
data: data[key]
});
}else {
res[key] = data[key];
}
});
}
return result;
}
注意,面试的时候写到第7点就行
转载自:https://juejin.cn/post/7134724081999413278