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

数组和对象深浅拷贝

对象浅拷贝

方法一:使用 Object.assign()

Object.assign() 方法用于将一个或多个源对象的所有可枚举属性复制到目标对象。它会返回目标对象。

const originalObj = {
    name: 'John',
    age: 30,
    hobbies: ['reading', 'running']
};

const shallowCopy = Object.assign({}, originalObj);

console.log(shallowCopy); 
// 修改浅拷贝对象的基本类型属性
shallowCopy.name = 'Jane';
console.log(originalObj.name); // John
console.log(shallowCopy.name); // Jane

// 修改浅拷贝对象的引用类型属性
shallowCopy.hobbies.push('swimming');
console.log(originalObj.hobbies); // ['reading', 'running', 'swimming']
console.log(shallowCopy.hobbies); // ['reading', 'running', 'swimming']
方法二:使用扩展运算符(...

扩展运算符可以将一个对象或数组展开。

const originalObj = {
    name: 'John',
    age: 30,
    hobbies: ['reading', 'running']
};

const shallowCopy = {...originalObj };

console.log(shallowCopy); 
// 修改浅拷贝对象的基本类型属性
shallowCopy.name = 'Jane';
console.log(originalObj.name); // John
console.log(shallowCopy.name); // Jane

// 修改浅拷贝对象的引用类型属性
shallowCopy.hobbies.push('swimming');
console.log(originalObj.hobbies); // ['reading', 'running', 'swimming']
console.log(shallowCopy.hobbies); // ['reading', 'running', 'swimming']
方法三:使用Object.create()
let a = {
  name: '艾总',
  like: {
    n: 'running'
  }

}
let b = Object.create(a)
a.name = '黎总'
console.log(a);
console.log(b);
console.log(b.name);
//{ name: '黎总', like: { n: 'running' } }
//{}
//黎总

数组浅拷贝

方法一:[].concat(arr)
let arr = [1, 2, 3, { a: 10 }]
let newArr = [1, 2].concat(arr)
arr[3].a = 100
console.log(arr);
console.log(newArr);
//[ 1, 2, 3, { a: 100 } ]
//[ 1, 2, 1, 2, 3, { a: 100 } ]
方法二:arr.slice(0)
arr = [1, 2, 3, 4, 5, { age: 18 }]
const arr1 = arr.slice(0)
arr[5].age = 20
console.log(arr);
console.log(arr1);
//[ 1, 2, 3, 4, 5, { age: 20 } ]
//[ 1, 2, 3, 4, 5, { age: 20 } ]
方法三:arr.toReversed().reverse()
arr = [1, 2, 3, 4, 5, { age: 18 }]
const arr1 = arr.toReversed().reverse()
arr[5].age = 20
console.log(arr);
console.log(arr1);
//[ 1, 2, 3, 4, 5, { age: 20 } ]
//[ 1, 2, 3, 4, 5, { age: 20 } ]
方法四:使用扩展运算符(...

扩展运算符可以将一个对象或数组展开。

对象深拷贝

方法一:使用 JSON.parse(JSON.stringify())

这是一种简单的深拷贝方法,但有一些局限性,比如不能处理函数、Symbol 类型的属性和 Date 对象等。

const originalObj = {
    name: 'John',
    age: 30,
    hobbies: ['reading', 'running']
};

const deepCopy = JSON.parse(JSON.stringify(originalObj));

console.log(deepCopy); 
// 修改深拷贝对象的基本类型属性
deepCopy.name = 'Jane';
console.log(originalObj.name); // John
console.log(deepCopy.name); // Jane

// 修改深拷贝对象的引用类型属性
deepCopy.hobbies.push('swimming');
console.log(originalObj.hobbies); // ['reading', 'running']
console.log(deepCopy.hobbies); // ['reading', 'running', 'swimming']
方法二:自定义递归函数

通过递归遍历对象的所有属性,复制每个属性的值。

使用typeof检测引用数据类型(如对象、数组、函数等)时,除了函数会返回 'function' 外,其他的引用数据类型都会返回 'object'

function deepClone(obj) {
    // 使用typeof检测引用数据类型(如对象、数组、函数等)时,
    // 除了函数会返回 'function' 外,其他的引用数据类型都会返回 'object'。
    //typeof 数组 会返回'object'
    //typeof 无法细致区分不同类型的引用数据,所以统一将数组归类为 'object'。
  
    if (typeof obj !== 'object' || obj === null) {
        //后续调用deepClone方法时如果是基本数据类型,会直接返回!!!
        return obj
    }
    let clone;
    if (Array.isArray(obj)) {
        clone = [];
        for (let i = 0; i < obj.length; i++) {
            clone[i] = deepClone(obj[i]);
        }
    } else {
        //进入这里代表obj是一个对象,对对象进行深拷贝时必须确保拷贝的属性是当前对象自身的属性

        clone = {}
        //  使用 for...in 循环进行遍历时,会遍历到对象原型链上的可枚举属性。
        for (let key in obj) {
            //所以使用obj.hasOwnProperty(key)进行确认
            if (obj.hasOwnProperty(key)) {
                clone[key] = deepClone(obj[key])
            }
        }
    }

    return clone;
}

const originalObj = {
    name: 'John',
    age: 30,
    hobbies: ['reading', 'running']
};

const deepCopy = deepClone(originalObj);

console.log(deepCopy);
// 修改深拷贝对象的基本类型属性
deepCopy.name = 'Jane';
console.log(originalObj.name); // John
console.log(deepCopy.name); // Jane

// 修改深拷贝对象的引用类型属性
deepCopy.hobbies.push('swimming');
console.log(originalObj.hobbies); // ['reading', 'running']
console.log(deepCopy.hobbies); // ['reading', 'running', 'swimming']

注意事项

  • 虽然 for...in 会遍历原型链上的可枚举属性,但现代 JavaScript 中很多内置对象的原型属性是不可枚举的,比如 Object.prototype 上的方法(toStringhasOwnProperty 等),所以 for...in 通常不会遍历到这些方法。
  • for...in 遍历属性的顺序是不确定的,不同的 JavaScript 引擎可能会有不同的实现,所以不要依赖 for...in 的遍历顺序。

相关文章:

  • JSP(学习自用)
  • 【火星】火星 数字地面模型(DEM)数字正射影像(DOM)下载
  • 【动手学轨迹预测】3.1 基于锚点的轨迹预测
  • Web后端 Tomcat服务器
  • Java零基础入门笔记:(1-2)入门(简介、基础知识)
  • AI前端开发与职业稳定性:ScriptEcho赋能下的未来展望
  • 【动态规划篇】:动态规划中的“双线叙述”--如何用状态转移解决双序列难题
  • Dify平台搭建面试机器人
  • [qt5学习笔记]Application Example示例程序源码解析
  • 【Java】 -- 顺序表的使用模拟实现
  • 如何选择合适的超参数来训练Bert和TextCNN模型?
  • Redis 深度解析:从基础到实践
  • 3D与2D机器视觉机械臂引导的区别
  • CMS DTcms 靶场(弱口令、文件上传、tasklist提权、开启远程桌面3389、gotohttp远程登录控制)
  • 深入探索 C++17 中的 std::hypot:从二维到三维的欧几里得距离计算
  • 日志2025.2.17
  • Prolog语言的Web开发
  • 计算机专业知识【原码、反码和补码的计算方法详解】
  • 拯救者电脑在重装系统之后电源计划丢失Fn+Q切换不了模式怎么恢复?
  • 微服务SpringCloudAlibaba组件sentinel教程【详解sentinel的使用以及流量控制、熔断降级、热点参数限流等,附有示例+代码】
  • c2c电子商务网站开发/百度推广下载安装
  • 网站定制化/网络营销模式下品牌推广研究
  • 建设旅游网站/搜外网友情链接
  • 科技 杭州 网站建设/微信推广平台哪里找
  • 分类信息网站 建议 建设/优化设计答案五年级上册
  • wordpress程序不能升级/seo短期课程