js对象拷贝方法
Object.create(),浅拷贝
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
递归
// 待拷贝的对象 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