- 使用递归方式进行深拷贝
- 通过JSON对象实现深拷贝
- 使用jq(extend)方法实现深拷贝
- object.assign()实现深拷贝
- lodash函数库实现深拷贝
- MessageChannel实现深拷贝
- Web Worker实现深拷贝
惊呆了!原来深拷贝有这么多种。。。
接下来我们逐一介绍下:
1.使用递归方式进行深拷贝:
function Clone(obj) {
//先判断是数组还是对象(执行对应的拷贝)
var objCopy = Array.isArray(obj) ? [] : {};
//拷贝的对象不能为空
if (obj && typeof obj === "object") {
for (key in obj) {//遍历
if (obj.hasOwnProperty(key)) {
//拷贝的对象不能为空
if (obj[key] && typeof obj[key] === "object") {
objCopy[key] = Clone(obj[key]);
} else {
objCopy[key] = obj[key];
}
}
}
}
return objCopy;
}2.JSON对象实现深拷贝
function Clone(obj) {
var Copyobj = JSON.stringify(obj),
//json字符串转json对象
objClone = JSON.parse(Copyobj);
return objClone;
}
*注意事项*
(2-1)如果obj里有RegExp、Error对象,则序列化的结果将只得到空对象
(2-2)如果obj里面有时间对象,则JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式。而不是时间对象
(2-3)如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失
(2-4)如果obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null
(2-5)无法处理function,无法处理循环引用对象
3.使用jq(extend)方法实现深拷贝
var obj= {
a:10,
b:function (){
console.log(this.a)
}
};
var newObj = $.extend(true,{},obj);
*注意*
$.extend中的true为深拷贝 false为浅拷贝
其实是把第二个对象上面的属性和对象覆盖到第一个对象上面
4.object.assign()实现深拷贝
var obj1 = { a: 0 , b: { c: 0}};
var obj2 = Object.assign({}, obj1);
*注意*
当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。
5.lodash函数库实现深拷贝
lodash很热门的函数库,提供了 lodash.cloneDeep()实现深拷贝
var abj={
a:1,
b:2
}
var copyobj = lodash.cloneDeep(abj)*注意*
层级太多的复杂对象拷贝可能会出现报错(其内部使用递归拷贝实现)
*/接下来看看几个偏门的深拷贝/*
6.MessageChannel实现深拷贝
let obj = { a: 1, b: { c: 2, d: 3, }, f: undefined } obj.c = obj.b; obj.e = obj.a obj.b.c = obj.c obj.b.d = obj.b obj.b.e = obj.b.c
function deepCopy(obj) { return new Promise((resolve) => { const {port1, port2} = new MessageChannel(); port2.onmessage = ev => resolve(ev.data); port1.postMessage(obj); }); }
deepCopy(obj).then((copy) => { // 请记住`MessageChannel`是异步的这个前提! let copyObj = copy; console.log(copyObj, obj) console.log(copyObj == obj) });*注意*
虽然能实现深拷贝,但拷贝有函数的对象时,还是会报错
(MessageChannel接口允许创建一个新的消息通道,并通过它的两个MessagePort属性发送数据。MessageChannel接口实例化以后,会有两个属性port1和port2.)
主要是用来做通道通信的
7.Web Worker实现深拷贝
var w1 = new Worker("worker1.js");
var w2 = new Worker("worker2.js");
var ch = new MessageChannel();
w1.postMessage("port1", [ch.port1]);
w2.postMessage("port2", [ch.port2]);
w2.onmessage = function(e) {
console.log(e.data);
}// worker1.js
onmessage = function(e) {
const port = e.ports[0];
port.postMessage("this is from worker1")
}// worker2.js
onmessage = function(e) {
const port = e.ports[0];
port.onmessage = function(e) {
postMessage(e.data)
}
}我们通过给w2绑定onmessage回调函数来验证传递是否成功输出this is from worker1
Web Workers 使得一个Web应用程序可以在与主执行线程分离的后台线程中运行一个脚本操作。这样做的好处是可以在一个单独的线程中执行费时的处理任务,从而允许主(通常是UI)线程运行而不被阻塞/放慢。