浅拷贝(Shallow Copy) VS 深拷贝(Deep Copy)
首先,深拷贝和浅拷贝针对的是对象类型(对象,数组,函数)。
浅拷贝指的是只是拷贝了对象的引用地址,彼此之间高耦合,一个改变,另一个可能也随之改变;
深拷贝是指只是完整的将变量的值拷贝过来,是一个新的对象,和被拷贝对象解耦合,一个改变,不会影响其它的内容。
浅拷贝
当对象有多层属性值时,只拷贝第一层, 是浅拷贝。如果被拷贝对象只有一层,下面的方法就是深拷贝。
1)对象遍历赋值
let copy = function(target,source){
for(let property in source){
target[property] = source[property]
}
return target;
}
2) 对象合并函数Object.assign({})--复制可遍历属性(元属性enumerable为true)
当Object.assign(obj)只有一个参数时,相当于返回自身。
let copy = Object.assign(obj); // copy === obj// 注意:当obj的值为原始类型的值(boolean,string,number)时,会将原始值转为包装对象。当obj为undefined或者null时,无法转为对象会报错。 当Object.assign(target, source1, source2,...)有多个参数时,将第一个设为空对象{}
// 浅拷贝
let copy = Object.assign({}, source);
// 注意: 当source为undefined或者null或者(boolean,number)时,会忽略source;当source为string类型时,会将字符串转为对象
Object.assign({},str) ---> //{0: "a", 1: "b", 2: "c"}
3)扩展运算符(...)性质同1)
let a = {
age: {
my: 18
}
}
let b = {...a};
b.age.my = 20;
a; //{age: {my: 20}}
4) [xxx].slice() 浅拷贝
var a = [[1,2,3]]; //目标对象是多维数组
var b = slice();
b[0][0] = 100;
a; // [[100,2,3]]
深拷贝
为了不出现上面例子中,嵌套关系拷贝只拷贝地址的情况,我们需要遍历到最底层,逐级赋值,实现深拷贝
1.JSON.parse(JSON.stringify(obj))
该方法可以解决大多数的深拷贝问题。实际开发任务中,基本都可以使用。但是有些特殊情况:
具体使用JSON.stringify的特殊的情况如下:
1)忽略属性值为undefined和function类型和Symbol类型的值;
JSON.parse(JSON.stringify({a:1, b:function(){}, c:undefined, d: Symbol()}))
// 结果如下:
{a: 1}
2) 值为Regex,Error类型的值会变成空对象{};
JSON.parse(JSON.stringify({a:1, b: RegExp('a'), c: new Error('err')}));
// 结果
{a:1, b: {}, c: {}}
3) 值NaN,Infinity,-Infinity的值会变成null;
JSON.parse(JSON.stringify({a:1, b: NaN, c:Infinity, d: -Infinity}))
// 结果
{a:1, b: null, c: null, d: null}
4)不能序列化循环引用的对象,会抛出异常
var a = {};
a.b = a;
JSON.stringify(a);
// Uncaught Error: Converting circular structure to JSON
5)当参数对象有自定义的toJSON()方法时,JSON.stringify()会将该方法的返回值作为最后的参数值,忽然其它的参数。
6)当参数值为Date对象类型时,因为Date对象有toJSON()方法,则JSON.stringify()会将Date类型的值按照字符串转换,
然后JSON.parse()去解析JSON字符串,最终会解析成字符串,不会解析成Date类型。
2.通用的深拷贝方法
1)直接使用lodash中的cloneDeep方法
2)手写一个深拷贝方法
function deepClone(obj, hash=new WeakMap()) {
// 如果obj为null/undefined
if(obj == null){// null == undefined
return obj;
}
if (obj instanceof RegExp) {
return new RegExp(obj); //拷贝正则对象,需要新生成一个对象
}
if (obj instanceof Date) {
return new Date(obj);
}
if(obj instanceof Error) {
return new Error(obj);
}
// 如果是原始类型的值(string/number/boolean/symbol)或者function
// function不需要被拷贝,使用时是调用
if(typeof obj !== 'object'){
return obj;
}
// 如果是对象(Array,Object)需要递归拷贝
if(hash.get(obj)) return hash.get(obj);
let cloneObj = new obj.constructor;
// 防止出现对象属性循环调用自身的情况: var a ={}; a.b= a;
hash.set(obj, cloneObj);
for(let key in obj) {
if (obj.hasOwnProperty(key)) {// 只拷贝自身的属性
cloneObj[key] = deepClone(obj[key], hash);
}
}
return cloneObj;
} //测试
var a = {a:1, b:function(){}, c:undefined, d: Symbol()};
var b = {a:1, b: RegExp('a'), c: new Error('err')};
var c = {a:1, b: NaN, c:Infinity, d: -Infinity};
var d = {a:1, b: new Date()}
var e = {}; e.a = e;
console.log(deepClone(a)); // {a:1, b:function(){}, c:undefined, d: Symbol()};
console.log(deepClone(b)); // {a:1, b: RegExp('a'), c: new Error('err')};
console.log(deepClone(b)); // {a:1, b: NaN, c:Infinity, d: -Infinity};
console.log(deepClone(d)); // {a:1, b: new Date()}
console.log(deepClone(e)); // {a: [Circular]}
浅拷贝(Shallow Copy) VS 深拷贝(Deep Copy)的更多相关文章
- 由Python的浅拷贝(shallow copy)和深拷贝(deep copy)引发的思考
首先查看拷贝模块(copy)发现: >>> help(copy)Help on module copy:NAME copy - Generic (shallow and dee ...
- [置顶] operator overloading(操作符重载,运算符重载)运算符重载,浅拷贝(logical copy) ,vs, 深拷贝(physical copy)
operator overloading(操作符重载,运算符重载) 所谓重载就是重新赋予新的意义,之前我们已经学过函数重载,函数重载的要求是函数名相同,函数的参数列表不同(个数或者参数类型).操作符重 ...
- copy&mutableCopy 浅拷贝(shallow copy)深拷贝 (deep copy)
写在前面 其实看了这么多,总结一个结论: 拷贝的初衷的目的就是为了:修改原来的对象不能影响到拷贝出来得对象 && 修改拷贝出来的对象也不能影响到原来的对象 所以,如果原来对象就是imm ...
- angular.extend深拷贝(deep copy)
在用到angular.extend的时候,正好碰到一个对象,是层层嵌套的Array, 结果发现只能extend第一层,查阅官文档,确实不支持deep copy: Note: Keep in mind ...
- [置顶] 运算符重载,浅拷贝(logical copy) ,vs, 深拷贝(physical copy),三大件(bigthree problem)
一般的我们喜欢这样对对象赋值: Person p1;Person p2=p1; classT object(another_object), or A a(b); classT object = ...
- 运算符重载,浅拷贝(logical copy) ,vs, 深拷贝(physical copy),三大件(bigthree problem)
一般的我们喜欢这样对对象赋值: Person p1;Person p2=p1; classT object(another_object), or A a(b); classT object = ...
- javascript 求最大前5个数; 对象 深拷贝 deep copy
* 用数组 function getTopN(a, n) { function _cloneArray(aa) { var n = aa.length, a = new Array(n); for ( ...
- python deep copy and shallow copy
Python中对于对象的赋值都是引用,而不是拷贝对象(Assignment statements in Python do not copy objects, they create bindings ...
- JS Object Deep Copy & 深拷贝 & 浅拷贝
JS Object Deep Copy & 深拷贝 & 浅拷贝 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Refe ...
随机推荐
- 102 - kube-scheduler源码分析 - cobra-寻找scheduler组件启动函数
main函数在哪里? 看到这个go文件时大家是不是有一种找到入口的欣喜,同时有一种难以言表的郁闷,为什么那么短?获取一个command,然后执行一个Execute()就运行了?好像是这么回事,然后点开 ...
- 推荐一款好用的任务定时器:Quartz
前言 官网:https://www.quartz-scheduler.net/ 一款开源的任务定时器. 日常有很多地方需要定时刷新的,比如微信开发中的微信API token,或者定时清理一下缓存数据等 ...
- JDK源码分析(11)之 BlockingQueue 相关
本文将主要结合源码对 JDK 中的阻塞队列进行分析,并比较其各自的特点: 一.BlockingQueue 概述 说到阻塞队列想到的第一个应用场景可能就是生产者消费者模式了,如图所示: 根据上图所示,明 ...
- 【我们一起写框架】MVVM的WPF框架(三)—数据控件
这世上,没人能一次性写出完美无缺的框架:因为,任何一个框架都需要项目的淬炼,然后才能升华,趋近完美. 所以,框架是个反复修改的东西,最终形成的东西. 如果你学了一点技术,觉得自己可以写出框架了,觉得自 ...
- python中的zip()函数和map()函数
一.zip()函数 1.语法: zip(iterable, ...) 参数说明: iterable,...-- 一个或多个迭代器; 在python2中: zip() 函数用于将可迭代的对象作为参数,将 ...
- 使用Boostrap框架写一个登录\注册界面
Bootstrap是一个Web前端开发框架,使用它提供的css.js文件可以简单.方便地美化HTML控件.一般情况下,对控件的美化需要我们自己编写css代码,并通过标签选择器.类选择器.ID选择器为指 ...
- 解决 Docker Image的UTF-8中文字符集的问题(以Oracle为例)
最近因业务需要,需要搭建一个Oracle数据库,当然Oracle数据库支持Linux,但是在上面搭建很是复杂,所以我想起了Docker ,果然在上面发现了一个OracleDB的镜像,所以下载之,运行, ...
- Mac10.12下Python3.4调用oracle
最近,由于项目的短信平台对其它浏览器兼容,只支持IE,但是我们移动端自动化需要测试iphone手机,必须要连接MAC系统下,众所周知,MAC对IE的不友好性,故没办法通过短信平台在UI层自动化获取短信 ...
- DataPipeline |《Apache Kafka实战》作者胡夕:Apache Kafka监控与调优
胡夕 <Apache Kafka实战>作者,北航计算机硕士毕业,现任某互金公司计算平台总监,曾就职于IBM.搜狗.微博等公司.国内活跃的Kafka代码贡献者. 前言 虽然目前Apache ...
- windows笔记本触摸板的快捷键教程
自从习惯了macbook的触摸板,根本就懒得使用鼠标.即实用,又便捷.但切换到windows笔记本的时候,总是不习惯使用触摸板. 今天查了一下微软的教程,发现windows现的已经做的相当不错了.但是 ...