相关理解
-
堆和栈
堆和栈是内存中划分出来用来存储的区域。栈为自动分配的内存空间,由系统自动来释放;而堆则是动态分配的内存,大小不定且不会自动释放。 -
ECAMScript数据类型
- 基本数据类型: string, number boolean symbol null undefined
存放在栈内存中,基本数据类型的数据大小确定,内存空间大小可以分配,是直接按值存放的,所以可以直接访问
基本数据类型值不可变,两个基本类型之间的比较就是值的比较 - 引用数据类型: String Number Boolean Object Function Array Date RegExp Error
存放在堆内存中,变量实际上是一个存放在栈内存中的指针,指针指向了堆内存中的地址。大小不同,需要动态分配。
引用数据类型的值是可以改变的,其比较是引用的比较,即看其引用是否指向了同一个对象
注意:闭包中的变量存在在堆内存中而非栈内存中。
- 基本数据类型: string, number boolean symbol null undefined
赋值与浅拷贝
-
赋值:
1.当基本数据类型进行赋值操作的时候,是在内存中开辟了一个新的栈内存,然后再把值赋值到新的栈内存中,因此基本类型赋值的两个变量是相互独立互不影响的。2.引用数据类型的赋值是传址,顾名思义就是说是对于对象保存在栈内存中的堆内存地址进行赋值,由此,两个变量就指向了同一个对象,因此其中一个改变,另外一个必将受到影响。
-
浅拷贝:
创建一个新对象,这个新对象有着原始对象属性值的一份精确拷贝
实例:- Object.assign(target, …sources)实现对对象的浅拷贝
target: 拷贝的目标 sources:源对象【可以为多个对象】
注意:- 只拷贝源对象的自身属性,不拷贝继承属性
- 不会拷贝对象不可枚举的属性
- undefined和null不可作为target, 可以作为source
- 属性名为
Symbol的属性是可以被object.assign拷贝的
- Array.prototype.slice实现对数组的浅拷贝
- Array.prototype.concat将数组和数组或和值连接在一起成新的数组
- …扩展运算符
实现浅拷贝
原理:新的对象复制已有对象中非对象属性的值和对象属性的引用。function shadowClone(sources) { var target = {}; for (var key in sources) { if(Object.prototype.hasOwnProperty.call(sources, key)) { target[key] = source[key]; } } return target; } - Object.assign(target, …sources)实现对对象的浅拷贝
-
深拷贝:
会拷贝一份一模一样的对象,从堆内存中开辟一个新的区域存放新对象,新对象与原对象不共享内存,修改新的对象不会改变原对象。实例:
- JSON.parse()/JSON.stringify()
JSON.stringify()把一对象序列化成一个json字符串,将对象的内容转换成字符串的形式再保存在磁盘上,在用JSON.parse()反序列化JSON字符串成为一个新的对象。【不可处理函数】
注意:- 拷贝的对象中存在函数,undefined,symbol则经过JSON.stringify()序列化后的字符串中这个键值会消失
- 无法拷贝不可枚举的属性,无法拷贝对象的原型链
- 拷贝Date引用类型会变成字符串
- 拷贝RegExp引用类型会变成空对象
- 对象中含有NaN、Infinity和-Infinity,则序列化的结果会变成null
- 无法拷贝对象的循环应用(即obj[key] = obj)
- 第三方深拷贝库lodash中_.cloneDeep()
实现深拷贝
原理:运用递归思想,遍历对象和数组直到里面所有为基本数据类型,然后再去复制。//定义检测数据类型的功能函数 function isObject(obj) { return typeof obj === Object && obj !== null; } function cloneDeep(source) { if (!isObject(source)) { return source; } var target = Array.isArray ? [] : {}; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key){ if (isObject(source[key])) { target[key] = cloneDeep(source[key]);//无法处理源对象内部循环引用的问题。 } else { target[key] = source[key]; } }) } } - JSON.parse()/JSON.stringify()
赋值、浅拷贝与深拷贝区别:
| 操作 | 和原数据是否指向同一对象 | 第一层数据为基本数据类型 | 原数据中包含子对象 |
|---|---|---|---|
| 赋值 | 是 | 改变使原数据一同改变 | 改变使原数据一同改变 |
| 浅拷贝 | 否 | 改变不会使原数据一同改变 | 改变使原数据一同改变 |
| 深拷贝 | 否 | 改变不会使原数据一同改变 | 改变不会使原数据一同改变 |
本文介绍了JS中赋值、浅拷贝与深拷贝的区别。先阐述了堆和栈的概念,以及基本数据类型和引用数据类型的存储方式。接着说明赋值时基本类型和引用类型的不同表现,浅拷贝和深拷贝的原理、实现方法及注意事项,如浅拷贝可通过Object.assign等实现,深拷贝可通过JSON.parse/stringify或lodash库实现。
287

被折叠的 条评论
为什么被折叠?



