- 基本类型:undefined,null,Boolean,String,Number,Symbol
- 引用类型:Object,Array,Date,Function,RegExp等
- 基本类型:基本类型值在内存中占据固定大小,保存在中(不包含中的变量)
- 引用类型:引用类型的值是对象,保存在中。而栈内存存储的是对象的变量标识符以及对象在堆内存中的存储地址(引用),引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。
注意:
- 中的变量并不保存在栈内存中,而是保存在堆内存中。这一点比较好想,如果中的变量保存在了中,随着外层中的函数从调用栈中销毁,变量肯定也会被销毁,但是如果保存在了堆内存中,内存函数仍能访问外层已销毁函数中的变量。看一段对应代码理解下:
- 本篇所讲的浅拷贝和深拷贝都是对于引用类型的,对于基础类型不会有这种操作。
看一段代码
基本数据类型复制配图:
结论:在栈内存中的数据发生数据变化的时候,系统会自动为新的变量分配一个新的之值在栈内存中,两个变量相互独立,互不影响的。
看一段代码
引用数据类型复制配图:
结论:引用类型的复制,同样为新的变量b分配一个新的值,报错在栈内存中,不同的是这个变量对应的具体值不在栈中,栈中只是一个地址指针。两个变量地址指针相同,指向堆内存中的对象,因此b.x发生改变的时候,a.x也发生了改变。
- 第一段代码:
从输出结果可以看出,浅拷贝后,数组a[0]并不会随着b[0]改变而改变,说明a和b在栈内存中引用地址并不相同。
- 第二段代码
从输出结果可以看出,浅拷贝后,数组中对象的属性会根据修改而改变,说明浅拷贝的时候拷贝的已存在对象的对象的属性引用。
- 浅拷贝定义
通过这个官方的浅拷贝函数分析:
新的对象复制已有对象中非对象属性的值和对象属性的引用。如果这种说法不理解换一种一个新的对象直接拷贝已存在的对象的对象属性的引用,即浅拷贝。
Object.assign
- 语法:
语法:Object.assign(target, ...sources)
ES6中拷贝对象的方法,接受的第一个参数是,剩下的参数是拷贝的(可以是多个)
- 举例说明:
从打印结果可以看出,是一个浅拷贝,它只是在根属性(对象的第一层级)创建了一个新的对象,但是对于属性的值是对象的话只会拷贝一份相同的内存地址。
- Object.assign注意事项
- 只拷贝源对象的自身属性(不拷贝继承属性)
- 它不会拷贝对象不可枚举的属性
- 和无法转成对象,它们不能作为参数,但是可以作为源对象
- 属性名为 值的属性,可以被Object.assign拷贝。
Array.prototype.slice
这个函数在浅拷贝概念定义的时候已经进行了分析,看上文。
Array.prototype.concat
- 语法
var new_array = old_array.concat(value1[, value2[, ...[, valueN]]])
参数:将数组和/或值连接成新数组
- 举例说明
Array.prototype.concat也是一个浅拷贝,只是在根属性(对象的第一层级)创建了一个新的对象,但是对于属性的值是对象的话只会拷贝一份相同的内存地址。
...扩展运算符
- 语法
var cloneObj = { ...obj };
- 举例说明
扩展运算符也是浅拷贝,对于值是对象的属性无法完全拷贝成2个不同对象,但是如果属性都是基本类型的值的话,使用扩展运算符也是优势方便的地方。
补充说明:以上4中浅拷贝方式都不会改变原数组,只会返回一个浅拷贝了原数组中的元素的一个新数组。
实现原理:新的对象复制已有对象中非对象属性的值和对象属性的,也就是说对象属性并不复制到内存。
- 实现代码:
- for in与hasOwnProperty函数说明,怕有些人小伙伴可能不清楚具体内容
for in
for...in语句以任意顺序遍历一个对象自有的、继承的、、非Symbol的属性。对于每个不同的属性,语句都会被执行。
hasOwnProperty
语法:obj.hasOwnProperty(prop)
prop是要检测的属性名称或者
该函数返回值为布尔值,所有继承了 Object 的对象都会继承到 hasOwnProperty 方法,和 in 运算符不同,该函数会忽略掉那些从原型链上继承到的属性和自身属性。
说了赋值操作和浅拷贝操作,大家是不是已经能想到什么是深拷贝了,下面直接说深拷贝的定义。
深拷贝会另外拷贝一份一个一模一样的对象,从堆内存中开辟一个新的区域存放新对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
JSON.parse(JSON.stringify())
JSON.stringify()是前端开发过程中比较常用的深拷贝方式。原理是把一个对象序列化成为一个JSON字符串,将对象的内容转换成字符串的形式再保存在磁盘上,再用JSON.parse()反序列化将JSON字符串变成一个新的对象
- 举例说明:
实现了深拷贝,当改变数组中对象的值时候,原数组中的内容并没有发生改变。JSON.stringify()虽然可以实现深拷贝,但是还有一些弊端比如不能处理函数等。
- JSON.stringify()实现深拷贝注意点
- 拷贝的对象的值中如果有函数,undefined,symbol则经过JSON.stringify()序列化后的JSON字符串中这个键值对会消失
- 无法拷贝不可枚举的属性,无法拷贝对象的原型链
- 拷贝Date引用类型会变成字符串
- 拷贝RegExp引用类型会变成空对象
- 对象中含有NaN、Infinity和-Infinity,则序列化的结果会变成null
- 无法拷贝对象的循环应用(即obj[key] = obj)
自己实现一个简单深拷贝
小伙伴们有没有什么好办法呢,可以写下代码在评论区一起讨论哦!
第三方深拷贝库
该函数库也有提供_.cloneDeep用来做 Deep Copy(lodash是一个不错的第三方开源库,有好多不错的函数,也可以看具体的实现源码)
用一张图总结
今天就分享这么多,如果对分享的内容感兴趣,可以关注公众号「程序员成长指北」,或者加入技术交流群,大家一起讨论。
进阶技术路线
加入我们一起学习吧!
版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/qdvuejs/39660.html