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

js 拷贝-包含处理循环引用问题

在 JavaScript 中,拷贝对象和数组时需要特别注意,因为对象和数组是引用类型,直接赋值只会复制引用,而不是实际的数据。以下是几种常见的拷贝方法及其应用场景:

1. 浅拷贝(Shallow Copy)

浅拷贝只会复制对象或数组的第一层,而不会递归复制其内部的嵌套对象或数组。

1.1 使用 Object.assign

Object.assign 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它只会复制第一层属性。

const obj1 = { a: 1, b: { c: 2 } };
const obj2 = Object.assign({}, obj1);

console.log(obj2); // 输出:{ a: 1, b: { c: 2 } }
console.log(obj2 === obj1); // 输出:false
console.log(obj2.b === obj1.b); // 输出:true 如果是深拷贝,这里应该是false。因为b是引用类型的数据
1.2 使用扩展运算符(Spread Operator)

扩展运算符 ... 可以用于对象和数组,实现浅拷贝。

const obj1 = { a: 1, b: { c: 2 } };
const obj2 = { ...obj1 };

console.log(obj2); // 输出:{ a: 1, b: { c: 2 } }
console.log(obj2 === obj1); // 输出:false
console.log(obj2.b === obj1.b); // 输出:true
1.3 使用 Array.prototype.slice 和扩展运算符

对于数组,可以使用 slice 和扩展运算符实现浅拷贝。

const arr1 = [1, 2, [3, 4]];
const arr2 = [...arr1];

console.log(arr2); // 输出:[1, 2, [3, 4]]
console.log(arr2 === arr1); // 输出:false
console.log(arr2[2] === arr1[2]); // 输出:true

2. 深拷贝(Deep Copy)

深拷贝会递归复制对象或数组的所有层级,包括嵌套的对象和数组。

2.1 使用 JSON.parseJSON.stringify

JSON.parseJSON.stringify 可以实现简单的深拷贝,但只适用于不含函数、undefinedDate 等特殊类型的对象,并且他也无法处理循环引用的问题。

const obj1 = { a: 1, b: { c: 2 } };
const obj2 = JSON.parse(JSON.stringify(obj1));

console.log(obj2); // 输出:{ a: 1, b: { c: 2 } }
console.log(obj2 === obj1); // 输出:false
console.log(obj2.b === obj1.b); // 输出:false
2.2 使用递归函数

可以编写一个递归函数来实现深拷贝。并且也可以解决循环引用的问题

function deepClone(objValue) {
    // 定义一个缓存的map
    const cache = new WeakMap() // 为什么用WeakMap 而不用Map,因为WeakMap 可以垃圾回收
    function _deepClone(obj) {
    //  判断是否是非对象类型(即基本数据类型)
        if (obj === null || (obj instanceof Object === false)) {
            return obj;
        }
       
        if (cache.has(obj)) {
         // 新增代码,查哈希表
            return cache.get(obj)
        }
        let target = Array.isArray(obj) ? [] : {}
        cache.set(obj, target)// 哈希表设值
        for (let i in obj) {
            // 判断是否是自身属性,而不是继承来的属性
            if (obj.hasOwnProperty(i)) {
                if (obj[i] instanceof Object === true) {
                // 判断是不是引用类型
                    target[i] = _deepClone(obj[i])
                } else {
                    target[i] = obj[i]
                }
            }
        }
        return target;
    }
    return _deepClone(objValue)
}
const obj1 = { a: 1, arr:[1,2,3] };
obj1.sub=obj1
obj1.arr.push(obj1)
const newObj= deepClone(obj1);

console.log(newObj.arr!==obj1.arr); // true
console.log(newObj.sub!== obj1.sub); // true
console.log(newObj.arr[3]!== obj1); // true
console.log(newObj.arr[3]=== newObj); // true

3. 使用第三方库

3.1 使用 Lodash 的 _.cloneDeep

Lodash 是一个功能丰富的 JavaScript 实用工具库,提供了 _.cloneDeep 方法来实现深拷贝。

import _ from 'lodash';

const obj1 = { a: 1, b: { c: 2 } };
const obj2 = _.cloneDeep(obj1);

console.log(obj2); // 输出:{ a: 1, b: { c: 2 } }
console.log(obj2 === obj1); // 输出:false
console.log(obj2.b === obj1.b); // 输出:false

总结

  • 浅拷贝:适用于不需要递归复制嵌套对象或数组的场景。

    • Object.assign
    • 扩展运算符 ...
    • Array.prototype.slice 和扩展运算符
  • 深拷贝:适用于需要递归复制嵌套对象或数组的场景。

    • JSON.parseJSON.stringify(不支持特殊类型)
    • 递归函数
    • 第三方库(如 Lodash 的 _.cloneDeep

根据实际需求选择合适的拷贝方法,可以高效地实现对象和数组的拷贝。

http://www.dtcms.com/a/122895.html

相关文章:

  • c++和python复制java文件到指定目录
  • AQS机制详解与总结
  • java方法07:加减乘除计算器
  • rkmpp 解码 精简mpi_dec_test.c例程
  • LeetCode 热题 100 题解记录
  • Docker Hello World
  • 计算机网络 实验三:子网划分与组网
  • GaussDB性能调优:从根因分析到优化落地
  • 10. git switch
  • Java MCP SDK 开发笔记(一)
  • 深度学习疑问--Transformer【3】:transformer的encoder和decoder分别有什么用?encoder是可以单独使用的吗
  • WHAT - React 进一步学习推荐
  • Electron 应用太重?试试 PakePlus 轻装上阵
  • LVM 扩容详解
  • 0 std::process::Command 介绍
  • 中小型网络拓扑图静态路由方式
  • 监测fastapi服务并自动拉起(不依靠dockerfile)
  • 低代码开发平台:飞帆画 echarts 仪表盘
  • Redis最佳实践——用户会话管理详解
  • 金陵幻境录——六朝古都的科技诗篇-南京
  • go游戏后端开发29:实现游戏内聊天
  • 用 HTML 网页来管理 Markdown 标题序号
  • 【微服务架构】SpringCloud Alibaba(九):分布式事务Seata使用和源码分析(TCC模式、Saga模式)
  • 分布式锁阿
  • 软件功能性测试有多重要?功能性测试工具有哪些?
  • Cocos Creator新手学习
  • day25学习Pandas库
  • mysql的主从复制
  • 中文语义相似度 + 去除标签后的网页文本(爬虫数据)
  • 彩色路径 第32次CCF-CSP计算机软件能力认证