讲清楚浅拷贝和深拷贝
先放出实现浅拷贝和深拷贝的一些方法(直接食用):
1.浅拷贝:
浅拷贝在拷贝对象的时候,对于对象最外一层实现的是普通的值拷贝,对于对象里面的对象是浅拷贝,只复制地址不复制地址对应的值。
/* 方法1.1:扩展运算符(最简单的方式)
*/
const originalObject = { a: 1, b: 2, c: {d: 3} };
const shallowCopy = { ...originalObject };originalObject.a = 10;
console.log(originalObject.a); // 输出 10
console.log(shallowCopy.a); // 输出 1originalObject.c.d = 11;
console.log(shallowCopy.c.d); // 输出 11
console.log(originalObject.c.d); // 输出 11
/* 方法2:Object.assign()
*/
const originalObject = { a: 1, b: 2, c: { d: 3} };
const shallowCopy = Object.assign({}, originalObject);
originalObject.a = 10;
originalObject.c.d = 11;console.log(originalObject.a); // 输出 10
console.log(shallowCopy.a); // 输出 1
console.log(originalObject.c.d); // 输出 11
console.log(shallowCopy.c.d); // 输出 11
/* 方法1.3:自定义函数实现浅拷贝
*/
function shallowCopyFun(obj) {// 只拷贝对象if (typeof obj !== 'object' || obj === null) {return obj;}// 根据 obj 的类型决定新对象是数组还是对象let newObj = Array.isArray(obj) ? [] : {};// 遍历 obj,并复制其自身属性到新对象for (let key in obj) {if (obj.hasOwnProperty(key)) {newObj[key] = obj[key];}}return newObj;
}
const originalObject = { a: 1, b: 2, c: { d: 3,e: 4 } };
const shallowCopy = shallowCopyFun(originalObject);originalObject.a = 10;
console.log(shallowCopy.a); // 输出 1
console.log(originalObject.a); // 输出 10originalObject.c.d = 11;
console.log(shallowCopy.c.d); // 输出 11
console.log(originalObject.c.d); // 输出 11
2.深拷贝
/* 方法2.1:Json对象实现深拷贝JSON 序列化和反序列化
*/
const originalObject = { a: 1, b: { c: 2 } };
const deepCopy = JSON.parse(JSON.stringify(originalObject));originalObject.b.c = 10;
console.log(originalObject.b.c); // 输出 10
console.log(deepCopy.b.c); // 输出 2
/* 方法2.2:递归函数实现
*/
function deepCopyFun(obj) {// 检查值是否是引用类型if (typeof obj !== "object" || obj === null) {return obj;}if (obj instanceof Date) {return new Date(obj);}if (obj instanceof RegExp) {return new RegExp(obj.source, obj.flags);}if (obj instanceof Function) {return obj;}// 初始化一个新的数组或对象let newObj = Array.isArray(obj) ? [] : {};for (let key in obj) {// 确保属性属于对象本身,不是继承的if (obj.hasOwnProperty(key)) {// 递归复制每个属性newObj[key] = deepCopyFun(obj[key]);}}return newObj;
}
const originalObject = { a: 1, b: { c: 2 } };
const deepCopy = deepCopyFun(originalObject);originalObject.b.c = 10;
console.log(originalObject.b.c); // 输出 10
console.log(deepCopy.b.c); // 输出 2
/* 方法2.3:concat实现深拷贝concat(arr1, arr2,...)
*/
var arr = [1,2,3]
var newArr = [].concat(arr)
arr.push(4)
console.log('arr:👉', arr);
console.log('newArr:👉', newArr);
/* arr:👉 [ 1, 2, 3, 4 ]newArr:👉 [ 1, 2, 3 ]
*/
/* 方法2.4:slice实现深拷贝slice(idx1, idx2)
*/
var arr = [1,2,3]
var newArr = arr.slice()
arr.push(4)
console.log('arr:👉', arr);
console.log('newArr:👉', newArr);
/* arr:👉 [ 1, 2, 3, 4 ]newArr:👉 [ 1, 2, 3 ]
*/
/* 方法2.5:lodash实现深拷贝_.cloneDeep(value)
value : 要深拷贝的值。
返回拷贝后的值
vue 中使用 :a. npm i --save lodash 下载依赖b. import _ from 'lodash' 在 组件 中引入 c. 用法和下面的一样
*/
var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false
/* 方法2.6:扩展符实现深拷贝
*/
var a=[1,2,3]
var b=[...a];
b.push(4);
console.log(b);//1,2,3,4
console.log(a)//1,2,3
为什么会有浅拷贝和深拷贝?这要从javaScript数据类型说起。分为基本数据类型和引用数据类型。
-
基本类型数据都是按照值访问的,直接保存和修改在变量里面实际的值。
值类型:在存储变量中存储的是值的本身,因此叫做值类型,即
string,Number,Boolean,Undefined,Null其中,基本数据类型null返回的是一个空的对象object,如果有一个变量我们以后打算存储为对象,默认值可以设置成null。 -
引用类型数据是按照引用访问的,即保存在变量对象中的是一个地址,该地址与堆内存的实际值相关联。
引用数据类型在存储变量中存储的仅仅是地址(引用),因此叫做引用数据类型。即通过
new关键字创建的对象(系统对象、自定义对象),如Object、Array、Date等。
操作系统控制栈,但是它不控制堆。具体堆栈理解可以自行bing!
-
引用类型的值是同时保存在栈内存和堆内存中的对象
javascript不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间,那我们操作啥呢? 实际上,是操作对象的引用, 所以引用类型的值是按引用访问的。 准确地说,引用类型的存储需要内存的栈区和堆区(堆区是指内存里的堆内存)共同完成,栈区内存保存变量标识符和指向堆内存中该对象的指针,也可以说是该对象在堆内存的地址。 -
基本数据类型-在百度上大多数都是说存在栈中的。从知乎回答找到正确答案link。即:
字符串: 存在堆里,栈中为引用地址,如果存在相同字符串,则引用地址相同。
数字: 小整数存在栈中,其他类型存在堆中。
其他类型:引擎初始化时分配唯一地址,栈中的变量存的是唯一的引用。
所以这里我们在来说说深拷贝和浅拷贝的区别:
- 浅拷贝:只复制指向某个对象的指针,而不是复制对象本身,新旧对象共享一块内存。
- 深拷贝:复制并创建一个一模一样的对象,不共享内存,修改新的对象,旧对象保持不变。
相关文章:
讲清楚浅拷贝和深拷贝
先放出实现浅拷贝和深拷贝的一些方法(直接食用): 1.浅拷贝: 浅拷贝在拷贝对象的时候,对于对象最外一层实现的是普通的值拷贝,对于对象里面的对象是浅拷贝,只复制地址不复制地址对应的值。 /* 方法1.1:扩…...
[足式机器人]Part2 Dr. CAN学习笔记- 最优控制Optimal Control Ch07
本文仅供学习使用 本文参考: B站:DR_CAN Dr. CAN学习笔记 - 最优控制Optimal Control Ch07-1最优控制问题与性能指标 1. 最优控制问题与性能指标2. 动态规划 Dynamic Programming2.1 基本概念2.2 代码详解2.3 简单一维案例 3. 线性二次型调节器ÿ…...
RedisInsight详细安装教程
简介 RedisInsight 是一个直观高效的 Redis GUI 管理工具,它可以对 Redis 的内存、连接数、命中率以及正常运行时间进行监控,并且可以在界面上使用 CLI 和连接的 Redis 进行交互(RedisInsight 内置对 Redis 模块支持)。 RedisIn…...
maven组件升级报错经验汇总
1. NosuchMethodError org.springframework.beans.factory.support.genericBeanDefinition(xxxxx) 2. ClassNotFoundException: org.springframework.boot.SpringApplication 可能冲突的依赖是: <dependency><groupId>org.springframework.boot</g…...
JS 中的 async 与 await
课程地址 有 4 个返回 Promise 对象的函数 ABCD,现在想让这 4 个 Promise 顺序执行: const isA true; const isB true; const isC true; const isD true;function A() {return new Promise((resolve, reject) > {console.log("running A&q…...
SQL 系列教程(六)
目录 SQL FOREIGN KEY 约束 SQL FOREIGN KEY 约束 创建表时的 FOREIGN KEY 约束 修改表时的 FOREIGN KEY 约束 撤销 FOREIGN KEY 约束 SQL CHECK 约束 SQL CHECK 约束 创建表时的 CHECK 约束 修改表的 CHECK 约束 撤销 CHECK 约束 SQL DEFAULT 约束 SQL DEFAULT 约…...
CocoaPods的安装和使用
前言 本篇文章讲述CocoaPods的安装和使用 安装cocoaPods 如果电脑没有安装过cocoaPods,需要先安装,使用下面的命令: sudo gem install cocoapods输入密码后开始安装,需要等待。。。但是我这里报错了。 The last version of d…...
Linux下软件安装的命令【RPM,YUM】及常用服务安装【JDK,Tomcat,MySQL】
Linux下软件安装的命令 源码安装 以源代码安装软件,每次都需要配置操作系统、配置编译参数、实际编译,最后还要依据个人喜好的方式来安装软件。这个过程很麻烦很累人。 RPM软件包管理 RPM安装软件的默认路径: 注意: /etc 配置文件放置目录…...
【linux】-telnet服务安装
1. 说明 telnet 分为 :telnet 服务端 和 telnet 客户端 本文只演示安装 telnet服务端 2. 安装telnet服务端、以及守护服务xinetd 2.1 检测telnet-server的rpm包是否安装 rpm -qa telnet-server 2.2 若未安装,则安装telnet-server࿰…...
安卓开发——Activity及常用布局和控件的使用
Activity及常用布局和控件的使用 一、实验目的 掌握Android常用布局和控件的使用。 Activity组件使用和Intent机制,加强对Activity生命周期的理解 二、实验设备及器件 Android Studio,图标:http://10.37.59.210/download/icon/MobileShopI…...
.net访问oracle数据库性能问题
问题: 生产环境相同的inser语句在别的非.NET程序相应明显快于.NET程序,执行时间相差比较大,影响正常业务运行,测试环境反而正常。 问题详细诊断过程 问题初步判断诊断过程: 查询插入慢的sql_id 检查对应的执行计划…...
vue上传解析excel表格并修改字段名
目录 1.安装 xlsx 2.引入 3.使用 1.安装 xlsx npm install xlsx 2.引入 import * as XLSX from xlsx; 3.使用 <template><div class"UploadCptOutbox"><div class"Tooloutbox"><el-uploadclass"upload"ref"u…...
jupyter notebook删除kernel & conda 删除虚拟环境
jupyter kernelspec list #列出jupyter的所有kernel jupyter kernelspec remove kernel_name #删除特定的kerneljupyter kernelspec list 命令可以在任何激活的环境中运行,无论是 base 环境还是某个虚拟环境。该命令将列出所有已注册的 Jupyter 内核,包括…...
Redis在生产环境中可能遇到的问题与解决方案(三)
11. Redis高可用问题 问题描述 在Redis集群中,当主节点发生故障时,需要快速切换到备用主节点,确保系统高可用。 解决方案 Redis Sentinel: 使用Redis Sentinel进行主从节点的监控和自动故障转移。 备用主节点: 配置…...
【C++干货铺】 RAII实现智能指针
个人主页点击直达:小白不是程序媛 C系列专栏:C干货铺 代码仓库:Gitee 目录 为什么需要智能指针? 内存泄漏 什么是内存泄漏,内存泄露的危害 内存泄漏的分类 堆内存泄漏(Heap leak) 系统资…...
【竞技宝jjb.lol】LOL:xiaohu岩雀天命抢龙扭转乾坤 WBG2-0轻取RA
北京时间2024年1月26日,英雄联盟LPL2024春季赛在昨天迎来第一周第四个比赛日,本日首场比赛由WBG对阵RA。本场比赛RA虽然在首局前期给了WBG很大的压力,但WBG还是凭借后期出色的团战配合拿下胜利,最终WBG2-0轻取RA。以下是本场比赛的…...
GoZero微服务个人探究之路(九)api文件编写总结
参考来源go-zero官方文档https://go-zero.dev/docs/tutorials 前言 go-zero是目前star最多的go语言微服务框架,api 是 go-zero特殊的语言,类型文件,go-zero自带的goctl可以通过.api文件生成http服务代码 api文件内容编写 不可使用关键字 …...
泛型..
1.泛型 所谓泛型 在类定义处是一种类型参数(我们平常所见到的参数指的就是方法中的参数 他接收有外界传递来的值 然后在方法中进行使用) 在类内部的话 则充当一种占位符 并且还提高了代码的复用率 何以见得提高了代码的复用率 其实就是通过对比使用了泛型技术和没有使用泛型技…...
Android App开发基础(1)—— App的开发特点
本文介绍基于Android系统的App开发常识,包括以下几个方面:App开发与其他软件开发有什么不一样,App工程是怎样的组织结构又是怎样配置的,App开发的前后端分离设计是如何运作实现的,App的活动页面是如何创建又是如何跳转…...
docker-compose初探
我一直直接使用docker命令来创建容器,没有怎么用过docker-compose。也不知道docker-compose和docker有什么区别,docker-compose有什么好处。 现在我约略认为,docker-compose是一个简化docker命令的工具,或者说,它是能…...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...
Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...
Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...
使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
