# 如何实现一个深拷贝 (cloneDeep)
更多描述
const obj = {
re: /hello/,
f() {},
date: new Date(),
map: new Map(),
list: [1, 2, 3],
a: 3,
b: 4,
};
cloneDeep(obj);
Issue
欢迎在 Gtihub Issue 中回答此问题: Issue 203 (opens new window)
Author
const oldJson = { a: 1 };
const newJson = JSON.parse(JSON.stringify(oldJson));
oldJson.a = 2;
console.log(oldJson); // {a: 2}
console.log(newJson); // {a: 1}
Author
const oldJson = { a: 1} const newJson = {} Object.assign(newJson, oldJson) oldJson.a = 2 console.log(oldJson) // {a: 2} console.log(newJson) // {a: 1}
Author
function getType(obj){ return Object.prototype.toString.call(obj).slice(8,-1); } function cloneDeep(obj){ let target = {}; if(getType(obj)==='Object'){ for(let key in obj){ let item = obj[key]; target[key]=cloneDeep(item); } return target; }else if(getType(obj)==='Array'){ return obj.map(item => cloneDeep(item) ) }else{ return obj; } }
var obj = {foo:function(){},bar:1,name:'cat'}
var objClone = cloneDeep(obj)
Author
- 如何处理复杂对象,如
Date
、Regexp
等 - 如何处理循环引用
Author
const oldJson = { a: 1} const newJson = {} Object.assign(newJson, oldJson) oldJson.a = 2 console.log(oldJson) // {a: 2} console.log(newJson) // {a: 1}
对于深层的复杂类型,assign 其实是浅拷贝
Author
/**
* 深拷贝关注点:
* 1. JavaScript内置对象的复制: Set、Map、Date、Regex等
* 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;
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 (Object.prototype.toString.call(source) === "[object Date]") {
result = new Date(source);
} else if (Object.prototype.toString.call(source) === "[object Regex]") {
result = new RegExp(source);
}
// 内置对象Set、Map
else if (Object.prototype.toString.call(source) === "[object Set]") {
result = new Set();
for (const value of source) {
result.add(deepClone(value, memory));
}
} else if (Object.prototype.toString.call(source) === "[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;
}
Author
(function (done) {
if (!done) return;
// 如何实现一个深拷贝 (cloneDeep)
const obj = {
re: /hello/,
f() {},
date: new Date(),
map: new Map(),
set: new Set(),
list: [1, 2, 3],
a: 3,
b: 4,
h: {
name: "wby",
age: 29,
},
e: undefined,
d: null,
};
let utils = getTypes();
const newObj = cloneDeep(obj);
console.log(newObj);
console.log(obj.map === newObj.map);
function getTypes() {
let isTypes = {};
function isTyping(typing) {
return function (value) {
return Object.prototype.toString.call(value) === `[object ${typing}]`;
};
}
let types = [
"Object",
"Function",
"RegExp",
"Map",
"Set",
"Date",
"Array",
"String",
];
for (let type of types) {
isTypes[`is${type}`] = isTyping(type);
}
return isTypes;
}
function cloneDeep(obj, memory) {
let target = Object.create(null);
memory || (memory = new WeakMap());
for (let key in obj) {
let value = obj[key];
if (typeof value !== "object" || value === null) {
target[key] = value;
} else {
if (utils.isSet(value)) {
target[key] = new Set();
for (const v of value) {
target[key].add(cloneDeep(v, memory));
}
} else if (utils.isMap(value)) {
target[key] = new Map();
for (const [k, v] of value.entries()) {
target[key].set(k, cloneDeep(v, memory));
}
} else if (utils.isObject(value)) {
target[key] = cloneDeep(value);
} else {
target[key] = new Object.prototype.constructor(value);
}
}
}
return target;
}
})(1);
Author
function deepCopy(obj) {
var result = Array.isArray(obj) ? [] : {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
if (typeof obj[key] === 'object') {
result[key] = deepCopy(obj[key]); //递归复制
} else {
result[key] = obj[key];
}
}
}
return result;
}
Author
const oldJson = { a: 1} const newJson = {} Object.assign(newJson, oldJson) oldJson.a = 2 console.log(oldJson) // {a: 2} console.log(newJson) // {a: 1} @kucy 对于数组等引用类型的属性值,Object.assign 还是浅拷贝