JavaScript浅拷贝和深拷贝怎么使用,用哪个合适
Admin 2022-07-05 群英技术资讯 770 次浏览
这篇文章主要介绍“JavaScript浅拷贝和深拷贝怎么使用,用哪个合适”,有一些人在JavaScript浅拷贝和深拷贝怎么使用,用哪个合适的问题上存在疑惑,接下来小编就给大家来介绍一下相关的内容,希望对大家解答有帮助,有这个方面学习需要的朋友就继续往下看吧。javascript中的对象是引用类型,在复制对象的时候就要考虑是用浅拷贝还是用深拷贝。
对象是引用类型,如果直接赋值给另外一个对象,那么只是赋值一个引用,实际上两个变量指向的同一个数据对象,如果其中一个对象的属性变更,那么另外一个也会变更。
示例1,简单示例:
let human1 = {
id: 1,
name: "happy"
};
human2 = human1; // 这里就是直接赋值
console.log(human1); // {id: 1, name: 'happy'}
console.log(human2); // {id: 1, name: 'happy'}
// 更改human1的名称,human2的也会更改
human1.name = "life";
console.log(human1); // {id: 1, name: 'life'}
console.log(human2); // {id: 1, name: 'life'}
示例2,对象作为参数传递也是传递引用:
let human1 = {
id: 1,
name: "happy"
};
console.log(human1); // {id: 1, name: 'happy'}
function foo(human) {
// 这里更改了human对象的名称
human.name = "life";
}
foo(human1); // 传递对象是传递引用
console.log(human1); // {id: 1, name: 'life'}
浅拷贝只是复制了对象的第一层,如果第一层的属性值是对象,那么该属性也只是复制了一个引用。
let object1 = {
a: 1,
b: { // b是对象
b1: 2
}
};
object2 = Object.assign({}, object1); // 这里就是浅拷贝,其中的b对象只复制了引用
// a是常规类型,不会互相影响
object1.a = 10;
console.log(object1.a); // 10
console.log(object2.a); // 1
// b是对象,会互相影响
object1.b.b1 = 20;
console.log(object1.b.b1); // 20
console.log(object2.b.b1); // 20
如果要实现完整的复制,就要使用深拷贝。
森拷贝就是不光是一层要复制,里面的层如果是对象也要进行复制。
如果对象可以确认是JSON对象,那么可以用JSON对象的方式。
沿用上面的例子:
let object1 = {
a: 1,
b: { // b是对象
b1: 2
}
};
object2 = JSON.parse(JSON.stringify(object1)); // 深拷贝
// a是常规类型,不会互相影响
object1.a = 10;
console.log(object1.a); // 10
console.log(object2.a); // 1
// b是对象,也不会互相影响
object1.b.b1 = 20;
console.log(object1.b.b1); // 20
console.log(object2.b.b1); // 2
这边深拷贝的原理其实就是先把对象转成json字符串,然后再转成json对象,中间转成json字符串后就和原来的对象没有关系了。
这方法的优点:实现非常简单。
缺点:
如果有属性值是函数的话,那么无法进行复制,数据会丢失。
另外原型对象无法进行复制。
所以这种方式只适合对象确认是一个纯粹的json数据。
因为需要一层一层递进复制,很容想到用递归的方式,参考如下实现:
function deepCopy(source) {
// 如果不是对象或者是null则直接返回
if (typeof source !== 'object' || source === null) {
return source;
}
let target = {};
// 遍历复制属性
for (let k in source) {
if (!source.hasOwnProperty(k)) {
continue;
}
if (typeof source[k] === 'object') { // 如果是对象,则递归复制
target[k] = deepCopy(source[k]);
continue;
}
let descriptor = Object.getOwnPropertyDescriptor(source, k);
Object.defineProperty(target, k, descriptor);
}
return target;
}
因为是一层一层复制,所以复制完成后,两个对象不会互相影响,并且也可以支持方法。
let object1 = {
a: 1,
b: { // b是对象
b1: 2
},
f: function() { // f是方法
console.log(3);
}
};
object2 = deepCopy(object1); // 深拷贝,也可以复制函数了。
object1.f(); // 3
object2.f(); // 3
// b是对象,也不会互相影响
object1.b.b1 = 20;
console.log(object1.b.b1); // 20
console.log(object2.b.b1); // 2
复制原型对象
但是这个方法还存在一个问题,就是原型对象无法复制,稍微改进一下:
// 把 let target = {}; 改成如下方式
// 保证原型也进行了复制
let target = Object.create(Object.getPrototypeOf(source));
这样就可以了,来个示例验证一下:
function Human() {
this.id = 1;
}
Human.prototype.bar = function() {
console.log("bar");
};
let human1 = new Human();
human2 = deepCopy(human1);
console.log("human1", human1);
console.log("human2", human2);
查看下两个对象的原型:
深拷贝复制原型对象:

完美复制。
当然这样的方法也存在一个问题,就是递归本身存在如果层次过深,容易造成栈溢出的问题。但是在实务中也建议不要复制非常大的对象,应该有另外好的解决方法。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
这篇我们来了解关于JS内存泄漏的相关内容,对于JS内存泄漏以及其影响有很多朋友是不知道,JS内存泄漏对我们正常的程序运行是有很大影响的,对此下文就给大家来解决JS内存泄漏和如何防止内存泄漏。
这篇文章主要介绍了如何用vue设计一个数据采集器,帮助大家更好的理解和学习使用vue框架,感兴趣的朋友可以了解下
不知道大家有没有玩过弹球消除方块的小游戏,也就是左右键控制最底端的一个小木板平移,接住掉落的小球,将球弹起后消除画面上方的一堆方块。本文就给大家分享用VUE+Canvas来实现一个弹球消除方块的小游戏,感兴趣的朋友就继续看吧。
这篇文章主要介绍了vue3函数setUp和reactive函数的相关知识及setup函数和reactive函数的注意点,通过具体代码给大家介绍的非常详细,需要的朋友可以参考下
什么是 React 高阶组件?聊聊怎么使用React高阶组件创建一个面包屑导航,希望对大家有所帮助!
成为群英会员,开启智能安全云计算之旅
立即注册关注或联系群英网络
7x24小时售前:400-678-4567
7x24小时售后:0668-2555666
24小时QQ客服
群英微信公众号
CNNIC域名投诉举报处理平台
服务电话:010-58813000
服务邮箱:service@cnnic.cn
投诉与建议:0668-2555555
Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008