947 字
5 分钟
手写系列-手写深拷贝
前言
什么是深拷贝?
简单理解: b 是 a 的一份拷贝,b 中没有对 a 中对象的引用 另一种理解: b 是 a 的一份拷贝,a、b 各自画图,a 与 b 没有连接
简单的方法
JSON 序列化与反序列化
let obj = {a:1,b:[2,3],c:{xx:4,yy:5}}let obj2 = JSON.parse(JSON.stringify(obj))obj2.a = 11obj2.b[0] = 11obj2.c.xx = 44console.log(obj) // {a:1,b:[2,3],c:{xx:4,yy:5}} 原先的obj不会被改变缺点:
- 不支持函数
- 不支持 undefind(因为 JSON 只有 null)
- 不支持日期(会把 date 变成 iso8601 格式的日期字符串)
- 不支持正则
- 不支持 Error 对象
- 不支持环状结构
- NaN Infinity 会变成 null
const obj = { a: "a", b: undefined, // undefinde 丢失 c: function () { // 函数丢失 console.log("this is a fnction"); }, d: NaN, // NaN 变为 null e: Infinity, // Infinity 变为 null f: new Date(), // 时间对象变为 iso8601格式字符串 g: /123/, // 正则 变为 空对象 h: new Error("error"), // 变为空对象};console.log(JSON.parse(JSON.stringify(obj)));// {a: 'a',d:null,e: null,f: 'iso8601格式字符串',g:{},h: {}}
obj.i = obj;console.log(JSON.parse(JSON.stringify(obj))); // 报错自己实现一个深拷贝
复制基本类型
基本类型:
- Number
- String
- Boolean
- Symbol
- undefined
- null
基本类型直接返回就好了
function deepClone(souce) { return souce;}引用类型 递归克隆
function deepClone(source) { if (source instanceof Object) { const dist = new Object(); for (let key in source) { dist[key] = deepClone(source[key]); } return dist; } else { return source; }}function deepClone(source) { if (source instanceof Object) { if (source instanceof Array) { // 数组 const dist = new Array(); for (let key in source) { dist[key] = deepClone(source[key]); } return dist; } else { // 普通对象 const dist = new Object(); for (let key in source) { dist[key] = deepClone(source[key]); } return dist; } } else { return source; }}if(source instance of Function){ const dist = function () { return source.apply(this, arguments); }; for (let key in source) { dist[key] = deepClone(source[key]); } return dist;}但是这种方法不会拷贝 length 属性 也就是函数形参个数 可以通过正则匹配函数体 函数参数 然后重新生成函数
const sourceString = source.toString();let body = sourceString.match(/(?<={)((\n*.*)*)(?=})/m)[0];let params = sourceString.match(/(?<=\().*(?=\))/)[0];dist = new Function(...params.split(","), body);else if (source instanceof RegExp) { dist = new RegExp(source.source, source.flags); for (let key in source) { dist[key] = deepClone(source[key]); } return dist}else if (source instanceof Date) { dist = new Date(source); for (let key in source) { dist[key] = deepClone(source[key]); } return dist}a = { name: "a" };a.self = a;a 就是环状结构 可以通过缓存的方式去拷贝环结构 在拷贝 a.self 的时候我们已经拷贝过 a 了 可以将 a 与 a 的深克隆结果缓存起来
const cache = []function deepClone(source){ if(source instanceof Object){ const sourceDist = cache.find((value) => value[0] === source)?.[1]; if (sourceDist) { return sourceDist; } else { let dist ... // 放在for 循环的上面 否则会进入死循环 cache.push([source,dist]) for (let key in source) { dist[key] = deepClone(source[key]); } return dist } }}最终代码
// 会有bug catch 没有清空 会有影响 可以用面向对象的方法解决const cache = [];module.exports = function deepClone(source) { // 判断是不是对象 if (source instanceof Object) { const sourceDist = cache.find((value) => value[0] === source)?.[1]; if (sourceDist) { return sourceDist; } else { let dist;
// 数组 if (source instanceof Array) { dist = new Array();
// 函数 } else if (source instanceof Function) { // dist = function () { // return source.apply(this, arguments); // };
const sourceString = source.toString(); let body = sourceString.match(/(?<={)((\n*.*)*)(?=})/m)[0]; let params = sourceString.match(/(?<=\().*(?=\))/)[0]; dist = new Function(...params.split(","), body);
// 正则 } else if (source instanceof RegExp) { dist = new RegExp(source.source, source.flags);
// 日期 } else if (source instanceof Date) { dist = new Date(source);
// 普通对象 } else { dist = new Object(); }
cache.push([source, dist]); for (let key in source) { // 跳过原型上的属性 if (source.hasOwnProperty(key)) { dist[key] = deepClone(source[key]); } } return dist; }
// 基本类型 } else { return source; }};