摘要:对象的浅拷贝浅拷贝是对象共用一个内存地址,对象的变化相互影响。这是特别值得注意的地方。和能正确处理的对象只有等能够被表示的数据结构,因此函数这种不能被表示的类型将不能被正确处理。
对象的浅拷贝:
浅拷贝是对象共用一个内存地址,对象的变化相互影响。比如常见的赋值引用就是浅拷贝:
let srcObj = {"name": "lilei", "age": "20"}; let copyObj = srcObj; copyObj.age = "22"; console.log("srcObj", srcObj); // srcObj { name: "lilei", age: "22" } console.log("copyObj", copyObj); // copyObj { name: "lilei", age: "22" }对象的深拷贝:
简单理解深拷贝是将对象放到一个新的内存中,两个对象的改变不会相互影响。
Object.assign()MDN上这样介绍Object.assign(),"Object.assign() 方法用于将所有可枚举的属性的值从一个或多个源对象复制到目标对象。它将返回目标对象",好吧,并看不出是深拷贝还是浅拷贝,我们来测试一下
let srcObj = {"name": "lilei", "age": "20"}; let copyObj2 = Object.assign({}, srcObj, {"age": "21"}); copyObj2.age = "23"; console.log("srcObj", srcObj); //{ name: "lilei", age: "22" }
看起来好像是深拷贝了,那其实这里let copyObj2 = Object.assign({}, srcObj, {"age": "21"}); 我们把srcObj 给了一个新的空对象。同样目标对象为 {},我们再来测试下:
srcObj = {"name": "明", grade: {"chi": "50", "eng": "50"} }; copyObj2 = Object.assign({}, srcObj); copyObj2.name = "红"; copyObj2.grade.chi = "60"; console.log("新 objec srcObj", srcObj); // { name: "明", grade: { chi: "60", eng: "50" } }
从例子中可以看出,改变复制对象的name 和 grade.chi ,源对象的name没有变化,但是grade.chi却被改变了。因此我们可以看出Object.assign()拷贝的只是属性值,假如源对象的属性值是一个指向对象的引用,它也只拷贝那个引用值。
也就是说,对于Object.assign()而言, 如果对象的属性值为简单类型(string, number),通过Object.assign({},srcObj);得到的新对象为‘深拷贝’;如果属性值为对象或其它引用类型,那对于这个对象而言其实是浅拷贝的。这是Object.assign()特别值得注意的地方。
多说一句,Object.assign({}, src1, src2); 对于scr1和src2之间相同的属性是直接覆盖的,如果属性值为对象,是不会对对象之间的属性进行合并的。
有很多第三方库实现了对象的深拷贝,比如常见的 Jquery 和 underscore ,比较未来的 lodash,实现源码还没仔细分析,分析之后再来补充。
不过,如果你没有引入这些库,对于深拷贝还有一个简单的方法实现
JSON.parse() 和 JSON.stringify() 算是对 深拷贝的一个无脑实现,看例子:
srcObj = {"name": "明", grade: {"chi": "50", "eng": "50"} }; // copyObj2 = Object.assign({}, srcObj); copyObj2 = JSON.parse(JSON.stringify(srcObj)); copyObj2.name = "红"; copyObj2.grade.chi = "60"; console.log("JSON srcObj", srcObj); // { name: "明", grade: { chi: "50", eng: "50" } }
可以看到改变copyObj2并没有改变原始对象,实现了基本的深拷贝。
但是用JSON.parse()和JSON.stringify()会有一个问题。
JSON.parse()和JSON.stringify()能正确处理的对象只有Number、String、Array等能够被json表示的数据结构,因此函数这种不能被json表示的类型将不能被正确处理。比如
srcObj = {"name": "明", grade: {"chi": "50", "eng": "50"}, "hello": function() {console.log("hello")}}; // copyObj2 = Object.assign({}, srcObj); copyObj2 = JSON.parse(JSON.stringify(srcObj)); copyObj2.name = "红"; copyObj2.grade.chi = "60"; console.log("JSON srcObj", copyObj2); //{ name: "红", grade: { chi: "60", eng: "50" } }
可以看出,经过转换之后,function丢失了,因此JSON.parse()和JSON.stringify()还是需要谨慎使用。
后续再补充深拷贝实现思想。。。。
数组的深拷贝和浅拷贝最后在补充一点数组的深拷贝和浅拷贝,同对象一样数组的浅拷贝也是改变其中一个会相互影响,比如:
let srcArr = [1, 2, 3]; let copyArr = srcArr; copyArr[0] = "0"; console.log("srcArr", srcArr); // ["0", 2, 3]
但是数组的深拷贝方法要相对简单一些可以理解为数组方法中那些会改变原数组的方法,比如
concat
slice
es6 的Array.from
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/93871.html
摘要:它将返回目标对象。有些文章说是深拷贝,其实这是不正确的。深拷贝相比于浅拷贝速度较慢并且花销较大。拷贝前后两个对象互不影响。使用深拷贝的场景完全改变变量之后对没有任何影响,这就是深拷贝的魔力。 一、赋值(Copy) 赋值是将某一数值或对象赋给某个变量的过程,分为: 1、基本数据类型:赋值,赋值之后两个变量互不影响 2、引用数据类型:赋址,两个变量具有相同的引用,指向同一个对象,相互之间有...
摘要:原文地址浅拷贝和深拷贝只针对像这样的复杂对象的简单来说,浅拷贝只拷贝一层对象的属性,而深拷贝则递归拷贝了所有层级。浅拷贝通过来实现浅拷贝。 原文地址:http://www.silenceboy.com/201... 浅拷贝和深拷贝只针对像Object, Array这样的复杂对象的.简单来说,浅拷贝只拷贝一层对象的属性,而深拷贝则递归拷贝了所有层级。 浅拷贝 通过 Object.ass...
摘要:引用类型值引用类型值是保存在堆内存中的对象,变量保存的只是指向该内存的地址,在复制引用类型值的时候,其实只复制了指向该内存的地址。 前言 要理解 JavaScript中浅拷贝和深拷贝的区别,首先要明白JavaScript的数据类型。JavaScript有两种数据类型,基础数据类型和引用数据类型。js的基本类型:undefined,null,string,boolean,number,s...
摘要:引用数据类型是存放在堆内存中的,变量实际上是一个存放在栈内存的指针,这个指针指向堆内存中的地址。栈和堆的区别其实浅拷贝和深拷贝的主要区别就是数据在内存中的存储类型不同。这里,对存在子对象的对象进行拷贝的时候,就是深拷贝了。 数据类型 在开始拷贝之前,我们从JavaScript的数据类型和内存存放地址讲起。数据类型分为基本数据类型 和引用数据类型 基本数据类型主要包括undefin...
摘要:基本类型指的是简单的数据段,而引用类型指的是一个对象保存在堆内存中的地址,不允许我们直接操作内存中的地址,也就是说不能操作对象的内存空间,所以,我们对对象的操作都只是在操作它的引用而已。 工作中经常会遇到需要复制 JavaScript 数据的时候,遇到 bug 时实在令人头疼;面试中也经常会被问到如何实现一个数据的深浅拷贝,但是你对其中的原理清晰吗?一起来看一下吧! 一、为什么会有深浅...
阅读 2161·2021-11-15 11:39
阅读 959·2021-09-26 09:55
阅读 879·2021-09-04 16:48
阅读 2792·2021-08-12 13:23
阅读 892·2021-07-30 15:30
阅读 2429·2019-08-29 14:16
阅读 843·2019-08-26 10:15
阅读 510·2019-08-23 18:40