公司建设网站的申请信用卡,任何查询网站有没有做404,携程做旅游的网站,外冈网站建设前言
在js中我们想要实现深拷贝#xff0c;首先要了解深浅拷贝的区别。 浅拷贝#xff1a;只是拷贝数据的内存地址#xff0c;而不是在内存中重新创建一个一模一样的对象#xff08;数组#xff09; 深拷贝#xff1a;在内存中开辟一个新的存储空间#xff0c;完完全全…前言
在js中我们想要实现深拷贝首先要了解深浅拷贝的区别。 浅拷贝只是拷贝数据的内存地址而不是在内存中重新创建一个一模一样的对象数组 深拷贝在内存中开辟一个新的存储空间完完全全的拷贝一整个一模一样的对象数组
1. MessageChannel实现深拷贝 MDN资料https://developer.mozilla.org/zh-CN/docs/Web/API/MessageChannel MDN中关于MessageChannel的介绍
Channel Messaging API 的 MessageChannel 接口允许我们创建一个新的消息通道并通过它的两个 MessagePort 属性发送数据。 备注 此特性在 Web Worker 中可用 使用方法
封装一个deepclone函数
function deppClone(obj) {return new Promise(resolve {const { port1, port2 } new MessageChannel()port1.postMessage(obj)port2.onmessage e {resolve(e.data)}})
}测试代码
function deppClone(obj) {return new Promise(resolve {const { port1, port2 } new MessageChannel()port1.postMessage(obj)port2.onmessage e {resolve(e.data)}})
}
const obj { a: , c: undefined, e: 0, f: [], g: NaN, h: null }
obj.b objlet newObj null
await deppClone(obj).then(res {newObj res
})console.log(obj, obj)
console.log(newObj, newObj)
console.log(obj newObj)
console.log(obj.b newObj)
console.log(obj newObj.b)结果 优点
他可以完美解决循环引用的问题。 支持的浏览器版本比较多 文献资料
缺点
不支持拷贝函数 不支持拷贝Symbol
2. structuredClone实现深拷贝 文献资料https://developer.mozilla.org/zh-CN/docs/web/api/structuredClone MDN中关于structuredClone()的介绍
全局的 structuredClone() 方法使用结构化克隆算法将给定的值进行深拷贝。
该方法还支持把原始值中的可转移对象转移到新对象而不是把属性引用拷贝过去。 可转移对象与原始对象分离并附加到新对象;它们不可以在原始对象中访问被访问到。
使用方法:
structuredClone(obj)测试代码
const obj { a: ,c:undefined,e:0,f:[],g:NaN,h:null }
obj.b objconst newObj structuredClone(obj)console.log(obj,obj)
console.log(newObj,newObj)
console.log(obj newObj)
console.log(obj.b newObj)
console.log(obj newObj.b)
结果 优点
他可以完美解决循环引用的问题。 而且非常简单调用API即可。
缺点
这是一个新的API它支持的浏览器版本比较新 不支持拷贝函数 不支持拷贝Symbol 3.手动封装deepClone函数
最经典的就是手动封装一个deepClone函数去主动判断传入类型并且递归创建新的对象
使用方法:
封装函数并判断类型
function isObject(value) {const valueType typeof valuereturn (value ! null) (valueType object || valueType function)
}function deepClone(originValue, map new WeakMap()) {// 判断是否是一个Set类型if (originValue instanceof Set) {return new Set([...originValue])}// 判断是否是一个Map类型if (originValue instanceof Map) {return new Map([...originValue])}// 判断如果是Symbol的value, 那么创建一个新的Symbolif (typeof originValue symbol) {return Symbol(originValue.description)}// 判断如果是函数类型, 那么直接使用同一个函数if (typeof originValue function) {return originValue}// 判断传入的originValue是否是一个对象类型if (!isObject(originValue)) {return originValue}if (map.has(originValue)) {return map.get(originValue)}// 判断传入的对象是数组, 还是对象const newObject Array.isArray(originValue) ? []: {}map.set(originValue, newObject)for (const key in originValue) {newObject[key] deepClone(originValue[key], map)}// 对Symbol的key进行特殊的处理const symbolKeys Object.getOwnPropertySymbols(originValue)for (const sKey of symbolKeys) {// const newSKey Symbol(sKey.description)newObject[sKey] deepClone(originValue[sKey], map)}return newObject
}测试代码
let s1 Symbol(aaa)
let s2 Symbol(bbb)const obj {a: 18,b: {c: www,d: {e: www}},// 数组类型hobbies: [abc, cba, nba],// 函数类型foo: function(m, n) {console.log(wwww)console.log(wwww)return 123},// Symbol作为key和value[s1]: abc,s2: s2,// Set/Mapset: new Set([aaa, bbb, ccc]),map: new Map([[aaa, abc], [bbb, cba]])
}obj.info objconst newObj deepClone(obj)
console.log(newObj obj)
console.log(obj,obj)
console.log(newObj,newObj)
console.log(newObj.s2 obj.s2)结果 优点
他可以完美解决各种问题。
4. JSON实现深拷贝
这是最不推荐使用的方法
优点这是最简单的方式了只能处理不复杂的对象
const symbol1 Symbol();
const obj { a: ,c:undefined,e:0,f:[],g:NaN,h:null,i:symbol1 }let newObj JSON.parse(JSON.stringify(obj))console.log(obj,obj)
console.log(newObj,newObj)缺点
不能解决循环引用 NaN问题 忽略Symbol()undefined 5.其他
比如lodash、jQuery等插件的实现方式就不多讲了。