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

深拷贝浅拷贝

1. 什么是浅拷贝?

浅拷贝不存在于基本数据类型当中, 只存在于引用数据类型中

对于基本类型而言: 如 String,Number, Boolean, null, undefined, Symbol, BigInt。这些值存储在栈内存中。当你把一个基本类型的值赋给另一个变量时,你是在复制这个值。

  let a = 10;let b = a; // 赋值a的值  b = 20;   console.log(a); // 10 (a 不受影响)

对于引用类型而言 : 主要是Object,包括ArrayFunctionDateRegExp (正则) 等。这些值的内容存储在堆内存中,而变量本身(在栈中)只存储一个指向堆内存地址的引用(指针)。所以浅拷贝只是对第一层的复制, 对于深层的属性是引用

const original = {name: "张三",age: 30,address: {city: "北京",street: "朝阳路"},skills: ["JavaScript", "HTML", "CSS"]
};// 2. 使用扩展运算符创建一个浅拷贝
const shallowCopy = { ...original };//... 扩展运算符或 Object.assign() 都是浅拷贝。console.log("---  1: 修改顶层的 '基本类型' ---");
// 我们修改浅拷贝的 name 属性
shallowCopy.name = "李四";
console.log("Original name:", original.name);     // 输出: "张三"
console.log("ShallowCopy name:", shallowCopy.name); // 输出: "李四"
// 结论: 顶层的基本类型是完全独立的。
console.log("\n---  2: 修改嵌套的 '对象' 属性 ---");
// 我们修改浅拷贝中 address 对象的 city 属性
shallowCopy.address.city = "上海";
console.log("Original city:", original.address.city);     // 输出: "上海" (被修改了!)
console.log("ShallowCopy city:", shallowCopy.address.city); // 输出: "上海"

2. 什么是深拷贝?

深拷贝就是创建一个全新的对象,这个新对象与原始对象完全独立,互不干扰。 深拷贝会递归地复制原始对象及其所有嵌套的子对象和数组,直到所有层级都是新创建的副本。

 let obj1 = { name: 'Alice', details: { age: 25 } };let obj3 = deepCopy(obj1); // 假设 deepCopy 是一个深拷贝函数obj3.details.age = 30;  console.log(obj1.details.age); // 25 (obj1 保持不变)

3. 如何实现深拷贝?

3.1 JSON.parse(JSON.stringify(obj))

  • JSON.stringify(obj): 将 JavaScript 对象序列化(转换)为一个 JSON 字符串。
  • JSON.parse(…): 将这个 JSON 字符串解析回一个新的 JavaScript 对象。
  let obj1 = {name: 'Alice',details: { age: 25 },skills: ['JS', 'CSS']};let obj2 = JSON.parse(JSON.stringify(obj1));obj2.details.age = 30;console.log(obj1.details.age); // 25 (未受影响)

优点: 能处理绝大多数纯数据对象(只包含对象、数组、字符串、数字、布尔值)

缺点:

  • 会丢失 undefined、Symbol、Function
  • 无法处理循环引用
  • 特殊对象会被转换 ( Date --> 日期字符串、RegExp -->{}、Map --> {}、Set --> {} 、NaN --> null、Infinity --> null )

3.2 structuredClone()

这是一个较新的、专门用于深拷贝的全局函数,现在已经被大多数现代浏览器和 Node.js支持。

  let obj1 = {name: 'Alice',joined: new Date(),skills: new Set(['JS', 'CSS']),metadata: new Map([['id', 123]])};let obj2 = structuredClone(obj1);obj2.skills.add('HTML');console.log(obj1.skills); // Set(2) { 'JS', 'CSS' } console.log(obj2.joined === obj1.joined); // false 

优点: 能正确处理 Date, RegExp, Map, Set, ArrayBuffer, Blob, File

缺点:

  • 无法克隆函数
  • 无法克隆原型链

3.3使用第三方库 (Lodash)

let obj1 = {name: 'Alice',details: { age: 25 },myFunc: () => console.log('hello')};let obj2 = _.cloneDeep(obj1);obj2.details.age = 30;console.log(obj1.details.age); // 25// Lodash 甚至可以(浅)复制函数console.log(obj1.myFunc === obj2.myFunc); // true (函数是浅复制的,这通常是期望行为)

优点: 相当健壮, 可以解决很多问题

缺点: 使用的时候需要为项目引入一个额外的库,增加了包的体积

3.4 自定义深拷贝

  • 支持基本类型 (string, number, boolean, null, undefined, symbol, bigint)。
  • 支持标准对象 ({}) 和数组 ([]).
  • 支持 Date, RegExp, Set, Map, ArrayBuffer, TypedArrays (如 Uint8Array)。
  • 正确处理循环引用 (使用 WeakMap)。
  • 保留原型链 (使用 Object.getPrototypeOf 和 Object.create)。
  • 复制 Symbol 属性 (使用 Reflect.ownKeys)。
  • 复制属性描述符 (enumerable, writable, configurable) 以及 getter 和 setter。
function deepClone(value, cache = new WeakMap()) {// 1. 处理基本类型和函数if (value === null || typeof value !== 'object') {return value;}// 2. 处理循环引用if (cache.has(value)) {return cache.get(value);}// 3. 处理特定的引用类型 (这些类型有特殊的内部结构)// 3.1. 日期 (Date)if (value instanceof Date) {const copy = new Date(value.getTime());cache.set(value, copy); // 存入缓存return copy;}// 3.2. 正则表达式 (RegExp)if (value instanceof RegExp) {const copy = new RegExp(value.source, value.flags);cache.set(value, copy); // 存入缓存return copy;}// 3.3. Setif (value instanceof Set) {// 重要:必须先创建空 Set 并立即存入缓存const copy = new Set();cache.set(value, copy);// 然后再递归地克隆 Set 中的每一个值value.forEach(item => {copy.add(deepClone(item, cache));});return copy;}// 3.4. Mapif (value instanceof Map) {// 重要:同 Set,必须先创建空 Map 并立即存入缓存const copy = new Map();cache.set(value, copy);// 然后再递归地克隆 Map 中的每一个键和值value.forEach((v, k) => {copy.set(deepClone(k, cache), deepClone(v, cache));});return copy;}// 3.5. 数组缓冲区 (ArrayBuffer)if (value instanceof ArrayBuffer) {const copy = value.slice(0); // ArrayBuffer.slice() 会创建新副本cache.set(value, copy);return copy;}// 3.6. 类型化数组 (TypedArrays, e.g., Uint8Array, Float64Array)if (ArrayBuffer.isView(value) && !(value instanceof DataView)) {const bufferCopy = deepClone(value.buffer, cache);const copy = new value.constructor(bufferCopy, value.byteOffset, value.length);cache.set(value, copy);return copy;}// 3.7. DataViewif (value instanceof DataView) {const bufferCopy = deepClone(value.buffer, cache);const copy = new DataView(bufferCopy, value.byteOffset, value.byteLength);cache.set(value, copy);return copy;}// 4. 处理普通对象 ({}) 和数组 ([])// 4.1. 保留原型链const proto = Object.getPrototypeOf(value);// 4.2. 创建新容器(对象或数组)const copy = (Array.isArray(value)) ? [] : Object.create(proto);// 4.3.在遍历属性前,立即将新创建的容器存入缓存cache.set(value, copy);// 5. 遍历并复制所有自有属性 (包括 Symbol 和不可枚举属性)// 5.1. 使用 Reflect.ownKeys 获取所有类型的键const keys = Reflect.ownKeys(value);for (const key of keys) {// 5.2. 获取原始属性描述符const descriptor = Object.getOwnPropertyDescriptor(value, key);if (!descriptor) continue;// 5.3. 复制属性描述符const newDescriptor = { ...descriptor };// 5.4. A: 如果是数据属性 (data property),递归克隆其值if (newDescriptor.hasOwnProperty('value')) {newDescriptor.value = deepClone(newDescriptor.value, cache);}// 5.5. 将新属性和描述符定义到克隆体上try {Object.defineProperty(copy, key, newDescriptor);} catch (e) {// 在某些严格模式或特定情况下 (例如克隆只读属性),defineProperty 可能会失败console.warn(`[deepClone] Could not define property "${String(key)}":`, e.message);}}return copy;
}
http://www.dtcms.com/a/532642.html

相关文章:

  • 样本与样本值
  • 无极网站网站首屏高度
  • ansible自动化运维入门篇-ansible部署
  • 如何在搜索中找到自己做的网站o2o电商交易类平台有哪些
  • Rust中错误处理机制
  • Ubuntu 24.04上安装MySQL 8.0
  • Java基于SpringBoot的高校报修与互助平台小程序【附源码、文档说明】
  • 工信部icp备案流程关键词在线优化
  • 做视频的模板下载网站ppt汇报模板免费下载
  • 10.16-10.25力扣计数刷题
  • 在K8s中部署多个ASP.NET Core实例
  • 14.如何利用ArcGIS将矢量线、面的坐标数据保存为txt
  • 网站开发者模式怎么打开做策划网站推广怎么写简历
  • zynq ttc pwm例子
  • 【底层机制】linux IO 为什么要有进程表项、文件表项、v节点表项、i节点表项
  • 怎么用wordpress修改网站源码镇江网站网站建设
  • 设计方案表网站名称汉台网站制作
  • git误合并两分支如何回退
  • 【Linux系统编程】编译器gcc/g++
  • LeetCode 面试经典 150_链表_K 个一组翻转链表(61_25_C++_困难)(四指针法;头插法)
  • 做一个简单网站多少钱建设银行网站买手机
  • Ubuntu 22.04上安装Vivado2023.1(离线方式)
  • 使用 OpenAI SDK 调用阿里云 Qwen 模型:从基础到提示词工程实战
  • HTTPS 高频考点
  • 安徽网站建设 网新线上推广100种方式
  • 东莞专业做网站优化用vs2010做网站登入
  • 若依框架学习第二天:功能改造与问题攻坚实战 (2)
  • 为什么要学深度学习?——从“传统编程”到“数据驱动”的思维跃迁(附AI落地案例)
  • 简述网站建设优坏的评价标准wordpress 手机访问不了
  • 浙江网站改版设计公司网站策划书结尾