当前位置: 首页 > news >正文

【前端面经】JS-深浅拷贝

理解深浅拷贝

深浅拷贝问题的出现是由于JavaScript对不同类型的存储方式而引发的。
对于原始数据类型,它们的值是直接存储在栈内存中;
而复杂数据类型,则在栈内存中记录它的指针,而指针指向堆内存中真正的值。
所以对于原始数据类型,就没有深浅拷贝一说;而对于复杂数据类型,浅拷贝就是仅复制指针,但被复制对象改变时,新复制的对象也会跟着改变;深拷贝则是连同堆内存中的数据完全拷贝一份,新旧对象的变化互不影响。

深浅拷贝的定义

浅拷贝:

拷贝复杂类型时,仅拷贝对象的指针;当原对象改变时,拷贝对象也会跟着改变。

深拷贝:

拷贝复制类型时,拷贝对象的值;当原对象改变时,拷贝对象不会跟着改变。

深浅拷贝的实现方案

浅拷贝方案:

  1. 展开运算符(ES6)
  2. Object.assign()
  3. concat

深拷贝:

  1. 手写递归
  2. JSON.parse(JSON.stringfy())
    • 先转换成字符串,再解析回对象
    • 缺点是不能处理正则表达式和函数等特殊数据类型
  3. 一些库封装的深拷贝方法,例如Lodash的_.cloneDeep()

手写实现

// 先写一个浅拷贝
function _deepClone(target) {let cloneRes = {};for(const key in target) {cloneRes[key] = target[key]}return cloneRes// 函数出口// if (typeof target !== 'obejct') return target
}// 2. 普通深拷贝(只考虑对象/非对象)
function _deepClone(target) {if (typeof target === 'object'){// 如果是对象,进行处理let cloneRes = {};for(const key in target) {cloneRes[key] = _deepClone(target[key])}return cloneRes} else {// 如果不是对象,直接返回return target}
}// 3.考虑数组的深拷贝
function _deepClone(target) {if (typeof target === 'object') {let cloneRes = Array.isArray(target) ? [] : {}; // 核心for (const key in target) {cloneRes[key] = _deepClone(target[key])}return cloneRes} else {return target}
}// 4. 考虑循环引用
// Q:为什么要用WeakMap替代Map?
// A:强引用和弱引用的区别,强引用只能手动释放,弱引用能够被垃圾回收机制释放,使用Map会造成内存额外消耗。
//    WeakMap中的键是弱引用,Map中的键是强引用
function _deepClone(target, map=new WeakMap()) {if (typeof target === 'object') {let cloneRes = Array.isArray(target) ? [] : {}; // 核心// 防止循环调用导致的栈内存溢出if (map.get(target)) {return map.get(target)}map.set(target, cloneRes)for (const key in target) {cloneRes[key] = _deepClone(target[key], map)}return cloneRes} else {return target}
}// 5. 考虑其他数据类型
function _deepClone (target, map = new WeakMap()) {if (target === null) return nullif (target instanceof Date) return new Date(target)if (target instanceof RegExp) return new RegExp(target);if (typeof target !== 'object') return targetif (map.get(target)) return map.get(target);let cloneRes = new target.constructor()map.set(target, cloneRes)for (const key in target) {if (target.hasOwnProperty(key)) {cloneRes[key] = _deepClone(target[key], map);}}return cloneRes
}
// 6. 性能优化
// 把for..in改为普通的for循环,性能会有所提高// 测试案例
const target = {field1: 1,field2: undefined,field3: {child: 'child'},field4: [2, 4, 8]
};
const newTarget = _deepClone(target)
newTarget.field4[1] = "Child2"
console.log(target);
console.log(newTarget);
console.log(target === newTarget);
// 输出:
// {
//   field1: 1,
//   field2: undefined,
//   field3: { child: 'child' },
//   field4: [ 2, 4, 8 ]
// }
// {
//   field1: 1,
//   field2: undefined,
//   field3: { child: 'child' },
//   field4: [ 2, 'Child2', 8 ]
// }
// false

参考链接&&相关文章

前端早读课【第2810期】JavaScript 深拷贝性能分析

http://www.lryc.cn/news/64113.html

相关文章:

  • 【自然语言处理】实验2布置:Word2Vec TransE案例
  • Redis集合底层实现原理
  • OVS常用命令与使用总结
  • 一以贯之:从城市网络到“城市一张网”
  • 【Java校招面试】基础知识(四)——JVM
  • 项目管理-计算专题(三点估算、PERT估算)
  • 【华为OD机试 2023最新 】模拟商场优惠打折(C语言题解 100%)
  • 使用TrieTree(字典树)来实现敏感词过滤
  • USB转串口芯片CH9101U
  • Java语言介绍
  • 终于把 vue-router 运行原理讲明白了(二)!!!
  • ChatGPT实现服务器体验沙箱
  • 【算法】刷题中的位运算
  • 9.Java中异常处理机制是什么
  • GeoTools实战指南: 叠加GeoTIFF与Shapefile图层生成截图
  • nginx配置sh脚本远程执行一键安装
  • Excel表格成绩排名全攻略,让你事半功倍!
  • Docker 持久化存储 Bind mounts
  • LVS +Keepalived 高可用群集部署
  • Kafka调优
  • Debezium系列之:详细介绍Debezium2.X版本导出Sqlserver数据库Debezium JMX指标的方法
  • 基于PWM技术的三相光伏逆变器研究(Simulink)
  • 〖Python网络爬虫实战㉑〗- 数据存储之JSON操作
  • 不得不说的行为型模式-责任链模式
  • 基于dsp+fpga+AD+ENDAC的半导体运动台高速数据采集电路仿真设计(四)
  • 快速搭建Electron+Vite3+Vue3+TypeScript5脚手架 (无需梯子,快速安装Electron)
  • 语义分割学习笔记(二)转置卷积
  • docker运行PostgreSQL数据库维护,执行脚本备份数据库与更新表结构
  • 【计算机网络】127.0.0.1、0.0.0.0、localhost地址是什么?
  • 分享2款CSS3母亲节主题寄语文字动画特效