Object.create(),浅拷贝
代码语言:javascript复制const clone = Object.create(
Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj)
);
Object.assign(targetObj,sourceObj),浅拷贝
不是深拷贝,循环引用、各种数据类型都可以拷贝,引用类型不是深拷贝
- 它不会拷贝对象的继承属性;
- 它不会拷贝对象的不可枚举的属性;
- 不可以拷贝对象中的对象;
- 可以拷贝 Symbol 类型的属性;
- 无法正确拷贝属性和属性
- 可以拷贝undefined/boolean/null/function/Date/RegExp/array/array中的对象;
参考阮一峰文档: https://es6.ruanyifeng.com/#docs/object-methods#Object-assign
扩展运算符,浅拷贝
不是深拷贝,循环引用、各种数据类型都可以拷贝,引用类型不是深拷贝
JSON.parse(JSON.stringfiy()),不完全深拷贝
- 拷贝的对象的值中如果有函数、undefined、symbol 这几种类型,经过 JSON.stringify 序列化之后的字符串中这个键值对会消失;
- 拷贝 Date 引用类型会变成字符串;
- 无法拷贝不可枚举的属性;
- 无法拷贝对象的原型链;
- 拷贝 RegExp 引用类型会变成空对象;
- 对象中含有 NaN、Infinity 以及 -Infinity,JSON 序列化的结果会变成 null;
- 无法拷贝对象的循环引用,如果对象中有循环引用,会报错:
Uncaught TypeError: Converting circular structure to JSON
递归
代码语言:javascript复制// 待拷贝的对象
let originObj = {
re: /hello/,
ff: function () {},
sym: Symbol(123),
date: new Date(),
mp: new Map(),
st: new Set(),
a: "aaa",
b: 123,
c: true,
d: undefined,
e: null,
f: {
f1: "fff",
f2: { a: "aaa", b: 123, c: true, d: undefined, e: null },
f3: [{ a: "aaa", b: 123, c: true, d: undefined, e: null }, "f666", 666],
},
g: [1, 2, 3],
h: [{ a: "aaa", b: 123, c: true, d: undefined, e: null }, "f666", 666],
};
var obj222 = {
a: originObj,
};
originObj.obj222 = obj222;
// 简单实现,缺点:没有考虑 Date/RegExp/Set/Map/循环引用,如果有循环引用会报错栈溢出
function cloneDeep(obj) {
let objClone = obj.constructor === Array ? [] : Object.create({});
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
// Object.prototype.toString.call(/123/)
if (obj[key] && typeof obj[key] === "object") {
objClone[key] = cloneDeep(obj[key]);
} else {
objClone[key] = obj[key];
}
}
}
return objClone;
}
// 详细实现
/**
* 深拷贝关注点:
* 1. JavaScript内置对象的复制: Set、Map、Date、RegExp等
* 2. 循环引用问题
* @param {*} object
* @returns
*/
function deepClone(source, memory) {
const isPrimitive = (value) => {
return /Number|Boolean|String|Null|Undefined|Symbol|Function/.test(
Object.prototype.toString.call(value)
);
};
let result = null;
let type = Object.prototype.toString.call(source);
memory || (memory = new WeakMap());
// 原始数据类型及函数
if (isPrimitive(source)) {
// console.log("current copy is primitive", source);
result = source;
}
// 数组
else if (Array.isArray(source)) {
result = source.map((value) => deepClone(value, memory));
}
// 内置对象Date、Regex
else if (type === "[object Date]") {
result = new Date(source);
} else if (type === "[object RegExp]") {
result = new RegExp(source);
}
// 内置对象Set、Map
else if (type === "[object Set]") {
result = new Set();
for (const value of source) {
result.add(deepClone(value, memory));
}
} else if (type === "[object Map]") {
result = new Map();
for (const [key, value] of source.entries()) {
result.set(key, deepClone(value, memory));
}
}
// 引用类型
else {
if (memory.has(source)) {
result = memory.get(source);
} else {
result = Object.create(null);
memory.set(source, result);
Object.keys(source).forEach((key) => {
const value = source[key];
result[key] = deepClone(value, memory);
});
}
}
return result;
}
console.log(cloneDeep(originObj));
console.log(deepClone(originObj));
参考:https://github.com/shfshanyue/Daily-Question/issues/203#issuecomment-888238489