Javascript Object.assgin()详解以及深浅拷贝

news/2025/6/13 8:58:15/

Object.assign() 方法是 JavaScript 中用于将所有可枚举属性的值从一个或多个源对象复制到目标对象的方法。它将返回目标对象。这是一种浅拷贝,也就是说,如果源对象中的属性是一个对象或数组,那么这个属性的引用将被复制,而不是对象的深层次拷贝。
语法
javascript
Object.assign(target, ...sources)
target: 目标对象,所有源对象的属性将被复制到这个对象上。
sources: 源对象,其可枚举属性会被复制到目标对象。
示例
基本用法
javascript
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };

const returnedTarget = Object.assign(target, source);

console.log(target);        // { a: 1, b: 4, c: 5 }
console.log(returnedTarget); // { a: 1, b: 4, c: 5 },与target相同,因为返回的就是target
对象属性的覆盖
如果目标对象与源对象中有同名属性,源对象的属性值会覆盖目标对象的属性值。
javascript
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };

Object.assign(target, source);
console.log(target.b); // 4,被source中的b覆盖了
多个源对象
可以从多个源对象中复制属性到目标对象,后面的源对象属性会覆盖前面的同名属性。
javascript
const target = { a: 1, b: 2 };
const source1 = { b: 4, c: 5 };
const source2 = { c: 6, d: 7 };

Object.assign(target, source1, source2);
console.log(target); // { a: 1, b: 4, c: 6, d: 7 }
浅拷贝
Object.assign() 只会进行浅拷贝,如果源对象的属性是引用类型(如对象或数组),那么复制的是引用,不是值。
javascript
const target = {};
const source = { a: { b: 2 } };

Object.assign(target, source);
console.log(target.a === source.a); // true,说明复制的是引用
避免覆盖目标对象原有属性
如果你不想改变目标对象,可以先用空对象作为目标对象,然后将结果赋值给新的变量。
javascript
const source = { a: 1, b: 2 };
const targetCopy = Object.assign({}, source);

console.log(targetCopy); // { a: 1, b: 2 }
注意事项
Object.assign() 不会复制源对象的不可枚举属性。
Object.assign() 也不会复制对象上的属性描述符(如 writable, enumerable, configurable)。
对于值为 null 或 undefined 的源对象,Object.assign() 不会抛出错误,但也不会进行任何复制操作。
使用 Object.assign() 可以在需要合并对象或复制对象属性时非常有用,但了解其浅拷贝的特性以及如何处理引用类型的属性是很重要的。

 

JavaScript中的深拷贝是一个常见但重要的概念,它指的是创建一个新的对象,这个新对象与原始对象完全独立,拥有自己独立的内存地址,修改新对象不会影响原始对象。下面是对JavaScript深拷贝的详细解析:
一、深拷贝与浅拷贝的区别
浅拷贝:只复制对象的第一层属性,如果属性是基本类型,则复制其值;如果属性是引用类型(如对象、数组),则复制其引用地址,即新旧对象共享同一个引用。
深拷贝:不仅复制对象的第一层属性,还递归地复制对象的所有嵌套属性,生成一个新的、完全独立的对象副本。
二、深拷贝的必要性
深拷贝在需要确保对象独立性、避免数据共享和意外修改的场景中尤为重要。例如,在状态管理、数据处理和表单数据处理等场景中,深拷贝能确保数据的完整性和安全性。
三、深拷贝的常见方法
JSON.parse(JSON.stringify(obj))
这是实现深拷贝的一种简单方法,通过将对象序列化为JSON字符串,然后再解析这个字符串得到一个新的对象。这种方法简单易用,但存在局限性,如无法处理函数、undefined、Symbol等特殊类型,也无法拷贝对象的原型链和循环引用对象。
递归实现深拷贝
通过递归遍历对象,对每个属性进行深拷贝。这种方法能够处理各种复杂的数据结构,但需要手动处理循环引用等特殊情况。
示例代码:
javascript
   function deepClone(obj, hash = new WeakMap()) {
       if (typeof obj !== 'object' || obj === null) {
           return obj;
       }
       if (hash.has(obj)) {
           return hash.get(obj);
       }
       const target = Array.isArray(obj) ? [] : {};
       hash.set(obj, target);
       Reflect.ownKeys(obj).forEach(key => {
           const val = obj[key];
           if (typeof val === 'object' && val !== null) {
               target[key] = deepClone(val, hash);
           } else {
               target[key] = val;
           }
       });
       return target;
   }
   
使用Lodash的cloneDeep方法
Lodash是一个非常流行的JavaScript工具库,其中的cloneDeep函数提供了强大的深拷贝功能,能够处理对象中的大多数复杂情况,包括循环引用。使用这种方法需要引入Lodash库。
示例代码:
javascript
   const _ = require('lodash');
   let obj1 = {name: "Alice", info: {age: 25}};
   let obj2 = _.cloneDeep(obj1);
   obj2.info.age = 30;
   console.log(obj1.info.age); // 输出: 25
   
使用structuredClone方法
structuredClone是一个新的API,它使用结构化克隆算法来实现深拷贝。该算法能够处理大多数复杂数据结构,如日期、正则表达式、循环引用等。不过,需要注意的是,较旧的浏览器版本可能不支持此方法。
示例代码:
javascript
   let obj1 = {name: "Alice", date: new Date(), info: {age: 25}};
   let obj2 = structuredClone(obj1);
   obj2.info.age = 30;
   console.log(obj1.info.age); // 输出: 25
   
四、注意事项
在使用深拷贝时,需要根据实际场景和数据结构选择合适的方法。
对于包含循环引用的对象,简单的递归方法可能无法正常工作,此时应考虑使用Lodash的cloneDeep或structuredClone方法。
深拷贝可能会增加程序的复杂性和性能开销,特别是在处理非常大的对象时,因此应谨慎使用。
综上所述,JavaScript中的深拷贝是一个重要的概念,掌握多种深拷贝方法对于开发高质量的应用程序至关重要。

 


http://www.ppmy.cn/news/1537537.html

相关文章

uni-app 实现APP版本更新的深度解析

版本更新是保持应用活力、修复漏洞、增强功能的重要手段。对于使用uni-app框架开发的跨平台应用而言,实现版本更新功能同样重要。本文将详细解析如何在uni-app项目中通过结合uni.request网络请求和plus.runtime API来实现应用的版本更新功能,并重点解析文…

【S32K3 RTD LLD篇5】K344 ADC SW+HW trigger

【S32K3 RTD LLD篇5】K344 ADC SWHW trigger 一,文档简介二,ADC SW HW 触发2.1 软硬件平台2.2 SWADC 软件触发2.3 SWBCTUADC 软件BCTU触发2.4 PITTRIGMUXADC 硬件PIT TRIGUMX触发2.5 EMIOSBCTUHWADC硬件EMIOS BCTU触发2.6 EMIOSBCTUHW LISTADC硬件EMIOS …

asp.net core Partial 分部视图、视图组件(core mvc 才支持)、视图、Razor组件 、razor pages

分部视图 》》》传参 》》两个东西换个名称,PartialView()>渲染视图>不带Layout 部分视图与普通视图没太大区别,它可以将重复使用的HTML内容结合起来,可以单独使用。 一般命名是在名称前面加下划线,放在/Views/Shared 目…

Spring Boot DevTools:如何关闭自动重启功能

目录 1. 什么是Spring Boot DevTools? 2. 为什么有时需要关闭自动重启? 3. 如何关闭自动重启? 方法 1: 修改 application.properties 文件 方法 2: 修改 application.yml 文件 方法 3: 使用环境变量 方法 4: 使用 Maven 配置 方法 5:…

深入理解栈(Stack)(纯小白进)

目录: 一、栈是什么?1. 栈的概念2.栈的结构选择 二、栈的实现1. 栈结构体的定义2. 栈的初始化3. 栈的销毁4. 入栈5.出栈6. 取栈顶元素7. 栈中元素的个数8. 判断栈是否为空 总结 一、栈是什么? 1. 栈的概念 栈(Stack)…

第七章 常见攻击事件分析--钓鱼邮件

简介 请勿在本机运行恶意文件样本 请勿在本机运行恶意文件样本 请勿在本机运行恶意文件样本 小张的公司最近遭到了钓鱼邮件攻击,多名员工的终端被控制做为跳板攻击了内网系统,请对钓鱼邮件样本和内网被攻陷的系统进行溯源分析,请根据小张备…

LeetCode Hot100 | Day1 | 二叉树:二叉树的直径

LeetCode Hot100 | Day1 | 二叉树:二叉树的直径 主要学习内容: 二叉树深度求法 深度的 leftright1 得到的是从根结点到叶子结点的节点数量 543.二叉树的直径 [543. 二叉树的直径 - 力扣(LeetCode)](https://leetcode.cn/prob…

压力测试指南-压力测试基础入门

压力测试基础入门 在当今快速迭代的软件开发环境中,确保应用程序在高负载情况下仍能稳定运行变得至关重要。这正是压力测试大显身手的时刻。本文将带领您深入了解压力测试的基础知识,介绍实用工具,并指导您设计、执行压力测试,最…