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

大白话JavaScript如何深拷贝一个对象或数组?JSON.parse (JSON.stringify ()) 这种方法有什么局限性?

如何深拷贝一个对象或数组

啥是深拷贝

深拷贝就像是给一个东西(对象或者数组)做了个完全一样的“克隆体”。这个“克隆体”和原来的东西没有任何关联,你对“克隆体”做任何修改,都不会影响到原来的东西,反过来也一样。

简单方法:JSON.parse(JSON.stringify())

这是一种比较简单的深拷贝方法。可以把它想象成,先把要拷贝的对象或者数组“翻译”成 JSON 格式的字符串,这个字符串就像是一个“蓝图”,然后再根据这个“蓝图”重新构建一个新的对象或者数组。

代码示例

// 定义一个对象
const originalObj = {
    name: '张三',
    age: 25,
    hobbies: ['篮球', '阅读']
};

// 使用 JSON.parse(JSON.stringify()) 进行深拷贝
const clonedObj = JSON.parse(JSON.stringify(originalObj));

// 修改克隆对象的属性
clonedObj.name = '李四';
clonedObj.hobbies.push('游泳');

console.log(originalObj); 
// 输出: { name: '张三', age: 25, hobbies: [ '篮球', '阅读' ] }
console.log(clonedObj); 
// 输出: { name: '李四', age: 25, hobbies: [ '篮球', '阅读', '游泳' ] }

从上面的代码可以看到,修改克隆对象的属性,原来的对象并没有受到影响。

手动实现深拷贝(递归方法)

手动实现深拷贝就是自己写代码来创建“克隆体”。对于对象和数组,需要递归地处理它们的每一个属性或者元素。

代码示例

function deepClone(target) {
    // 如果目标不是对象或者数组,直接返回
    if (typeof target!== 'object' || target === null) {
        return target;
    }

    let clone;
    // 判断是数组还是对象
    if (Array.isArray(target)) {
        clone = [];
        // 遍历数组元素
        for (let i = 0; i < target.length; i++) {
            // 递归调用深拷贝函数
            clone[i] = deepClone(target[i]);
        }
    } else {
        clone = {};
        // 遍历对象属性
        for (let key in target) {
            if (target.hasOwnProperty(key)) {
                // 递归调用深拷贝函数
                clone[key] = deepClone(target[key]);
            }
        }
    }
    return clone;
}

// 定义一个对象
const original = {
    name: '王五',
    info: {
        address: '北京'
    }
};

// 使用自定义深拷贝函数
const cloned = deepClone(original);

// 修改克隆对象的属性
cloned.info.address = '上海';

console.log(original); 
// 输出: { name: '王五', info: { address: '北京' } }
console.log(cloned); 
// 输出: { name: '王五', info: { address: '上海' } }

这个自定义的 deepClone 函数会检查目标是对象还是数组,然后递归地处理每一个属性或者元素,确保“克隆体”和原来的东西完全独立。

JSON.parse(JSON.stringify()) 方法的局限性

1. 无法处理函数和正则表达式

JSON.stringify() 会忽略对象中的函数和正则表达式,因为 JSON 格式不支持这些类型。这就好比在画“蓝图”的时候,把函数和正则表达式这些“特殊零件”给漏掉了。

代码示例

const obj = {
    name: '赵六',
    sayHello: function() {
        console.log('你好');
    },
    reg: /abc/
};

const clonedObj = JSON.parse(JSON.stringify(obj));

console.log(clonedObj); 
// 输出: { name: '赵六' }

可以看到,sayHello 函数和 reg 正则表达式都没有被拷贝。

2. 无法处理 undefinedSymbol 类型

JSON.stringify() 会忽略对象中的 undefinedSymbol 类型的属性。这就像在“蓝图”里把这些类型的属性当成不存在一样。

代码示例

const obj = {
    name: '孙七',
    age: undefined,
    [Symbol('key')]: 'value'
};

const clonedObj = JSON.parse(JSON.stringify(obj));

console.log(clonedObj); 
// 输出: { name: '孙七' }

age 属性和 Symbol 类型的属性都没有被拷贝。

3. 无法处理循环引用

循环引用就是对象的属性指向了对象本身或者形成了一个循环的引用关系。JSON.stringify() 遇到循环引用会报错,就像“蓝图”画到一半发现陷入了一个死循环,不知道该怎么画下去了。

代码示例

const obj = {};
obj.self = obj;

try {
    const clonedObj = JSON.parse(JSON.stringify(obj));
} catch (error) {
    console.log(error); 
    // 输出: TypeError: Converting circular structure to JSON
}

这里 objself 属性指向了 obj 本身,JSON.stringify() 处理时就会报错。

相关文章:

  • ss命令——查看网络连接信息
  • vue+qrcode2批量生成二维码
  • 【Python爬虫(74)】用Python爬虫解锁法律条文数据的宝库
  • C语言 --- 经典习题1
  • 使用 C# 以api的形式调用 DeepSeek
  • 千峰React:案例一
  • IDEA 使用codeGPT+deepseek
  • 绕过【information_schema】,【order by】过滤
  • git 国内源
  • Mobaxterm服务器常用命令(持续更新)
  • 001 Kafka入门及安装
  • 【快速入门 LVGL】-- 1、STM32 工程移植 LVGL
  • IO 和 NIO 有什么区别?
  • 网页无法加载的常见原因及解决方法
  • 如果更换ip地址会怎么样?网络ip地址怎么更换
  • Spring 源码硬核解析系列专题(八):Spring Security 的认证与授权源码解析
  • Unity3D 实现骨骼动画的 GPU Skinning 详解
  • 大连本地知识库的搭建--数据收集与预处理_01
  • 【Project】基于Prometheus监控docker平台
  • Vue组件:从使用到原理的深度解析
  • 网站建设策划书5000字/如何推广网站方法
  • 帮别人做诈骗网站技术/海洋网络推广效果
  • 分销网站建设/最新网站查询工具
  • 合肥有多少建网站公司/谷歌浏览器手机版
  • 宁波专业定制网站建设/浙江seo关键词
  • 网销怎么找客户/网站优化流程