JS 中的 assign 方法究竟是 “深克隆” 还是 “浅克隆”?
先说一下答案:assign做的是浅克隆。
“第一层是深克隆,下面的每一层做的是浅克隆” 这种说法其实是错误的。
在我们去探究assign是深克隆还是浅克隆之前,我们必须先明白究竟什么是深克隆、什么是浅克隆?
问了一位大佬,是这么回答的
深浅克隆本质是看克隆后有没有指向同一个内存空间 - 牛客_上岸酱
这就是深、浅克隆的核心区别,网上有数不胜数的回答,但很少有这句话分析地如此简单而又透彻。
回顾一下assign的用法
let obj2 = Object.assign({}, obj1);
assign发挥的作用,就是将obj1的属性克隆到一个空对象(取决于obj1的数据类型)中,然后让obj2指向这个对象。
我们一起看一个例子:
let obj1 = {m: 1,n: 2,attr: {name: 'Jack',age: 18}
}let obj2 = Object.assign({}, obj1);obj1.attr.name = 'Tom';
console.log( obj1.attr.name ); // Tom
console.log( obj2.attr.name ); // Tomobj2.attr.name = 'Jarry';
console.log( obj1.attr.name ); // Jarry
console.log( obj2.attr.name ); // Jarry
可以看到,obj1与obj2的attr依旧是耦合的状态,所以,很明显assign做的就是浅克隆。
还有很多人说,第一层是深克隆,更深的依旧是浅克隆
首先,这种说法一定是错误的。
按照这种说法,由obj1克隆出obj2,assign做的是深克隆。
但我们仔细观察上面的代码,obj2指向的对象,其实并非由assign创建,而是事先由我们创建。assign做的,只是将obj1的属性,克隆到这个事先被我们创建好的空对象中罢了。
注意事项:
- assign在做属性拷贝过程,可能会产生异常,比如目标对象的某个只读属性和源对象的某个属性同名,这时该方法会抛出一个 TypeError 异常,拷贝过程中断,已经拷贝成功的属性不会受到影响,还未拷贝的属性将不会再被拷贝。
- Object.assign() 拷贝的是属性值。假如源对象的属性值是一个指向对象的引用,它也只拷贝那个引用值。
它无法实现多层的深克隆
我们来实现一个简单的多层深克隆:
function deepCopy(o,c){var c = c || {}for(var i in o){if(typeof o[i] === 'object'){// 要考虑深复制问题了if(Object.prototype.toString.call(o[i]).slice(8, -1) === Array){// 这是数组c[i] =[];}else{//这是对象c[i] = {}}deepCopy(o[i],c[i])}else{c[i] = o[i]}}return c
}
这个方法只能作为一种思路,其在真正的应用中,还是会出现很多的问题。
- 例如出现循环对象该如何处理?(a对象某个属性指向b对象,b对象中某个属性又是指向a对象)
- 当对象的属性较多、深度够大时,使用递归,在性能上,也有很大的问题。
目前,最好的解决方式,就是 lodash 中的 .cloneDeep(value) 方法,对ES6新增加的大多数数据类型都有考虑,性能上也是十分不错的。
JS 中的 assign 方法究竟是 “深克隆” 还是 “浅克隆”?相关推荐
- JS中通过call方法实现继承
JS中通过call方法实现继承 原文:JS中通过call方法实现继承 讲解都写在注释里面了,有不对的地方请拍砖,谢谢! <html xmlns="http://www.w3.org/1 ...
- JS中的Replace方法
最近查一个bug,原因是JS中的Replace方法造成的,当将一个字符串中有处需要替换时,一般会用到JS中的Replace方法,Replace方法的第一个参数如果是传的字符串,只会替换第一处.代码如下 ...
- java script eval_「eval」js中的eval方法详解(一)–eval方法的初级应用 - seo实验室...
eval 在我看来,js中的eval()方法就是一个js语言的执行器,它能把其中的参数按照javaScript语法进行解析并执行. 语法: eval(s); eval()方法中的参数s有多种情况.参数 ...
- JS中创建对象的方法
JS中创建对象的方法 最近手头一个项目刚完成,下一个显目还在准备中,趁这个空档期,拿起尘封多年的JS书, 重温一遍JS面向对象程序设计,然后就得出下文,算是一个总结吧. 也许,你会说 "创建 ...
- jquery中的map()方法与js中的map()方法
1.jquery中的map()方法 首先看一个简单的实例: $("p").append( $("input").map(function(){ return $ ...
- js中的字符串方法与数组方法总结
js中的字符串方法与数组方法总结 1.字符串方法 2.数组方法
- 请尽可能说出js中数组的方法,最少3个,越多越好
我接下来要把数组方法全都过一遍,顺手做个整理. 至于为什么整理这个,最近总听说面试经常会问到这个问题, 面试官灵魂发问:请尽可能说出js中数组的方法,最少3个,越多越好 据可靠消息了解到,如果你回答的 ...
- slice在php里面什么意思,js中slice()使用方法
本文主要和大家分享js中slice()使用方法,slice()通过索引位置获取新的数组,该方法不会修改原数组,只是返回一个新的子数组. 用法:arrayObj.slice(start,end)arra ...
- js中的slice方法(开始索引,结束索引-不包含该索引元素)-截取和splice方法-删除(开始索引,删除个数)和插入-(开始索引,删除个数,插入内容)
js中的slice方法(开始索引,结束索引-不包含该索引元素)-截取和splice方法-删除(开始索引,删除个数)和插入-(开始索引,删除个数,插入内容) 1.slice(start,end)-截取 ...
最新文章
- html属性选择器怎么写,html – 具有“type”属性与make-up属性的CSS属性选择器和区分大小写...
- 20170914-构建之法:现代软件工程-阅读笔记
- 【数据结构】线性表大咖
- wampserver一系列问题总结
- 数据分析与挖掘建模实战003:单因子探索分析与可视化001数据案例介绍
- c语言课程设计--拼图游戏,C语言课程设计_拼图游戏.pdf
- ajax加载时间长,如何最好地处理需要很长时间才能完成的ajax请求?
- 「HNOI 2015」实验比较
- zeal刷新不出来_热血传奇:计算怪物刷新时间,升级速度立马不同,老玩家笑出了声。...
- UG 6.0软件安装教程
- 【重识云原生】第六章容器6.1.3节——Docker常用命令
- 最优化算法之鲍威尔算法(java)
- Trafodion建表之使用多温度特性
- 程序员转正答辩ppt
- PivotGridControl与ChartControl控件结合使用(一)
- 杂题 P1640 [SCOI2010]连续攻击游戏
- kafka报错:Replication factor:larger than available brokers
- 分治法解决赛程安排问题
- 如何考上复旦大学研究生
- 4000块一晚,住进地下88米深坑,这是全国首家AI超五星酒店