JavaScript 深浅拷贝原理以及内部代码实现过程
说到深浅拷贝,必须先提到的是JavaScript的数据类型值,分为基本数据类型值和引用数据类型值
基本数据类型指的是简单的数据段:
1.Underfied 2.Null 3.Boolean 4.Number 5.String 6.Symbol (es6新增)
引用类型的值指的是可能包含多个值的对象
为什么要把数据类型这样分呢?本质上,是因为基本数据类型保存在栈内存,引用数据类型保存在堆内存中。那再进一步问:为什么要分两种保存方式呢? 根本原因在于保存在栈内存的必须是大小固定的数据,引用类型的大小不固定,只能保存在堆内存中,但是我们可以把它的地址写在占内存中以供我们访问。贴两个别人文章的图详细说明一下:
图1:
var a = 1;//定义了一个number类型 var obj1 = { name:'Ljf'};//定义了一个引用类型
所以上面这段代码执行后,内存空间是这样:
注:
var a = 1; var b = a;//复制 console.log(b)//1 a = 2;//改变a的值 console.log(b)//1
所以我们发现复制完b以后,即使改变a的值,b也不会改变,因为a和b是相互独立的,按照上面的图,也就是在栈内存中创建了一个变量b保存的值是1
图2:
var color1 = ['red','green']; var color2 = color1;//复制 console.log(color2)//['red','green']; color1.push('black') ;//改变color1的值 console.log(color2)//['red','green','black']
上面这段代码执行后,内存空间是这样:
注:图2结果我们发现只是复制了一次引用类型的地址而已,所以,不管接下来我们是操作color1还是color2,本质上都是操作同一个数组对象。
言归正传,我们现在来讲下深浅拷贝。其实对于基本数据类型的拷贝,并没有深浅拷贝的区别,我们所说的深浅拷贝都是对于引用数据类型而言的
1.浅拷贝:
① " = "符号赋值操作
上面的代码是最简单的利用 = 符号赋值操作符实现了一个浅拷贝,可以很清楚的看到,随着 newArray 和 newObject改变,originalArray 和 originalObject也随着发生了变化
② “首层浅拷贝”:对目标对象的第一层进行深拷贝,然后后面的是浅拷贝
我们验证了 originalObject=== newObject 是 false,说明这两个对象引用地址不同。originalObject 中关于a没被影响,但是d中的对象被修改了。
结论:从 shallowClone 的代码中我们可以看出,我们只对第一层的目标进行了 深拷贝 ,而第二层开始的目标我们是直接利用 "="符号赋值操作符进行拷贝的,所以,第二层后的目标都只是复制了一个引用,也就是浅拷贝
JavaScript 中Array.prototype.concat() ,Array.prototype.slice(),Object.assign{} … 展开运算符 这些自带的拷贝方法都是都是“首层浅拷贝”2.深拷贝:
① JSON.parse(JSON.stringify())的方法(就是利用JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反序列化(还原)js对象)
确实是深拷贝,也很方便。但是这个方法只能适用于一些简单的情况。特殊情况如下:
MDN: If undefined, a function, or a symbol is encountered during conversion it is either omitted (when it is found in an object) or censored to null (when it is found in an array). JSON.stringify can also just return undefined when passing in "pure" values like JSON.stringify(function(){}) or JSON.stringify(undefined).
大概意思就是undefined、function、symbol 会在转换过程中被忽略(还有很多种情况,比如对象中有Error对象,NaN等等都是不同结果)
所以上述例子中对象中含有一个函数,就不能用JSON.parse(JSON.stringify())进行深拷贝。
② 递归的方法
所以带有函数的对象进行深拷贝用递归就行
结论:JSON.parse(JSON.stringify()) 实现的是深拷贝,但是对目标对象有要求;若想真正意义上的深拷贝,用递归。
- [Android开发] 在项目中快速实现 列表字母排序滑动索引 功能原理以及过程代码
- c++中深浅拷贝以及写时拷贝的实现示例代码
- JavaScript 专题系列第六篇,讲解深浅拷贝的技巧和以及实现深浅拷贝的思路
- VC点滴 之 WinMain(windows程序的运行原理以及VC++的实现过程)
- IntentService实现原理及内部代码
- 决策树(1)ID3原理以及代码实现
- javascript,com组件打印,以及纯script代码实现局部页面打印
- StartActivity的内部代码实现原理
- AsyncTask实现原理和内部代码
- javascript高逼格代码实现数组去重,JSON深度拷贝,匿名函数自执行,数字取整等
- windows程序的运行原理以及VC 的实现过程
- 执行具有root权限的java代码 am pm的实现过程原理
- I/O模型和原理,以及简单解析客户端请求WEB服务器内部处理过程,MPM三种模
- Session生命周期以及内部实现原理
- SDWebImage底层实现原理及内部实现过程
- ContentProvider和Cursor以及CursorAdapter三者之间内部链接实现原理 解析
- javascript 方法实现千位分隔符以及代码解释
- C# j基本操作-拷贝文件夹的所有内容到另一个文件夹内: 复制代码 1 public static void CopyDir(string srcPath, string实现文件夹的复制以及删除
- 动网论坛上传文件漏洞的原理以及攻击的代码实现