基础
深拷贝和浅拷贝
深拷贝
深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象(新旧对象不共享同一块内存),且修改新对象不会影响原对象(深拷贝采用了在堆内存中申请新的空间来存储数据,这样每个可以避免指针悬挂
// 拷贝对象和数组
JSON.parse(JSON.stringify())使用 JSON.stringfify 几个问题
1、会忽略 undefined
2、会忽略 symbol
3、不能序列化函数
4、不能解决循环引用的对象
5、不能正确处理new Date()
6、不能处理正则
浅拷贝
如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址(新旧对象共享同一块内存),所以如果其中一个对象改变了这个地址,就会影响到另一个对象(只是拷贝了指针,使得两个指针指向同一个地址)
浅拷贝和赋值
当我们把一个对象赋值给一个新的变量时,赋的其实是该对象的在栈中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的
浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。即默认拷贝构造函数只是对对象进行浅拷贝复制(逐个成员依次拷贝),即只复制对象空间而不复制资源。
简单来说可以理解为浅拷贝只解决了第一层的问题,拷贝第一层的基本类型值,以及第一层的引用类型地址。
浅拷贝实现
const obj1 = {
name: "Chen",
hobby: ["see a film", "write the code", "play basketball", "tourism"],
};
const arr1 = [
{
name: "Chen",
},
"see a film",
"write the code",
"play basketball",
"tourism",
];- 展开运算符
- Object.assign
- Array.prototype.concat()
- Array.prototype.slice()
// 展开运算符
const obj2 = {...obj1}// Object.assign
const obj3 = Object.assign({}, obj1)// Array.prototype.concat()
const arr2 = arr1.concat([]);// Array.prototype.slice()
const arr2 = arr1.slice()2.Object.assign()
Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign() 进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。
Object.assign(target, ...sources)内存机制
js 内存管理 JavaScript 的内存管理由引擎负责, 本质是维护一个从 GC Root 出发的对象可达图。 V8 通过分代回收,新生代采用复制算法, 老生代采用标记清除和标记整理,并通过增量、并行、并发 GC 降低 Stop-The-World 时间。 内存泄漏的根本原因是对象在逻辑上已无用,但在可达性图中仍然可达。
V8 Heap ├── New Space 新生代 │ ├── Eden │ └── Survivor ├── Old Space 老生代 ├── Large Object Space ├── Code Space ├── Map Space └── Read-Only Space
- 新生代:小(几 MB) 回收算法:Scavenge 复制 存活对象复制 未复制对象 = 被回收
- Old Space:经历多次 GC 仍存活、To-Space 放不下 标记阶段:DFS/BFS 遍历对象图 清除阶段:回收未标记对象 整理阶段:移动存活对象、消除碎片 老生代 GC = 最容易造成卡顿
- 大对象空间(LOS):不经过新生代、直接进 LOS、不会复制 大对象是 GC 性能杀手 常见内存泄漏:
- dom 未使用
- 事件监听未移除
- 闭包
为什么 GC 会卡顿? -->JS 是单线程 标记阶段必须“世界停止”
内存泄漏:
- JS --> DOM 的双重系统 DOM 不在 V8 Heap 在浏览器 C++ 堆中 JS 只保存引用 let el = document.querySelector('#app') document.body.removeChild(el) // el 仍被 JS 引用