对象的深拷贝和浅拷贝

news2024/11/22 21:56:43

深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型的。

数据类型

数据分为基本数据类型(String, Number, Boolean, Null, Undefined,Symbol)和对象数据类型。

  • 基本数据类型的特点:直接存储在栈(stack)中的数据
  • 引用数据类型的特点:存储的是该对象在栈中引用,真实的数据存放在堆内存里

引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。

浅拷贝和 深拷贝区别

  • 浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。
  • 深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

赋值和浅拷贝的区别

当我们把一个对象赋值给一个新的变量时,赋的其实是该对象的在栈中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的。
浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。即默认拷贝构造函数只是对对象进行浅拷贝复制(逐个成员依次拷贝),即只复制对象空间而不复制资源。

var obj = {
    name: 'mary',
    age: 18,
    hobby: [1, [2, 3], [4, 5]],
}

var obj2 = obj;
obj2.name = 'lsit'
obj2.hobby[1] = ['二', '三']
console.log('obj', obj)
console.log('obj2', obj2)

var obj = {
    name: 'mary',
    age: 18,
    hobby: [1, [2, 3], [4, 5]],
}

var obj3 = shollowCopy(obj);
obj3.name = 'list';
obj3.hobby[1] = ['二', '三']

function shollowCopy(oldobj) {
    var newArr = {};
    for (var i in oldobj) {
        if (oldobj.hasOwnProperty(i)) {
            newArr[i] = oldobj[i]
        }
    }
    return newArr
}
console.log('obj', obj)

浅拷贝的实现方式

Object.assign()

Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign()进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。

var obj = { a: { a: 'mary', b: 39 } }
var newObj = Object.assign({}, obj);
newObj.a.a = 'ssss'
console.log('newObj', newObj)

注意:当object只有一层的时候,是深拷贝

Array.prototype.concat()

var arr = [1, 2, { 'userName': 'mary' }]
var arr2 = arr.concat();
arr2[2].userName = 'ssss'
console.log('arr', arr)
console.log('arr2', arr2)

Array.prototype.slice()

var arr = [1, 2, { 'userName': 'mary' }]
var arr2 = arr.slice();
arr2[2].userName = 'ssss'
arr2[0] = 3
console.log('arr', arr)
console.log('arr2', arr2)

Array的slice和concat方法的补充说明:Array的slice和concat方法不修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。

原数组的元素会按照下述规则拷贝:

如果该元素是个对象引用(不是实际的对象),slice 会拷贝这个对象引用到新的数组里。两个对象引用都引用了同一个对象。如果被引用的对象发生改变,则新的和原来的数组中的这个元素也会发生改变。对于字符串、数字及布尔值来说(不是 String、Number 或者 Boolean 对象),slice 会拷贝这些值到新数组里。在别的数组里修改这些字符串或数字或是布尔值,将不会影响另一个数组。

深拷贝的实现方式

JSON.parse(JSON.stringify())

用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。

var arr = [1, 2, { 'userName': 'mary' }]
var arr4 = JSON.parse(JSON.stringify(arr))
arr4[2].userName = 'sss'
console.log('arr', arr)
console.log('arr4', arr4)

这种方法虽然可以实现数组或对象深拷贝,但不能处理函数,这是因为JSON.stringify() 方法是将一个JavaScript值(对象或者数组)转换为一个 JSON字符串,不能接受函数

千万不要用JSON.stringify()去实现深拷贝!有巨坑!! - 掘金

手写递归

递归方法实现深度克隆原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝

//监测数据类型的函数
function checkedType(target) {
    return Object.prototype.toString.call(target).slice(8, -1)
}

// 实现深度克隆
function deepClone(target) {
    // 判断拷贝的数据类型
    // 初始化变量result
    var result, targetType = checkedType(target)
    if (targetType === 'Object') {
        result = {}
    } else if (targetType === 'Array') {
        result = []
    } else {
        return target
    }
    // 遍历目标数据
    for (var i in target) {
        // 获取便利数据结构的每一项值
        let value = target[i]
        // 判断目标结构里的每一值是否存在对象/数组
        if (checkedType(value) === 'Object' || checkedType === 'Array') {
            result[i] = deepClone(value)

        } else {
            result[i] = value
        }
    }
    return result
}
var obj = [1, 2, { "useranme": 'mary' }, [3, 4]]
var newObj = deepClone(obj)
newObj[2].useranme = 'ssss'
console.log('obj', obj)
console.log('newObj', newObj)

函数库lodash

该函数库也有提供_.cloneDeep用来做 Deep Copy


 


 


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/826138.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微信小程序选项卡切换(滑动切换,点击切换)

效果如下&#xff1a;可点击切换&#xff0c;滑动切换 代码如下 这个可以在项目用 index.wxml <view classtopTabSwiper><view classtab {{currentData 0 ? "tabBorer" : ""}} data-current "0" bindtapcheckCurrent>选项一&…

移动端商品分类左右联动

代码&#xff1a; <template><view class"u-wrap"><view class"u-menu-wrap"><scroll-view scroll-y scroll-with-animation class"u-tab-view menu-scroll-view" :scroll-top"scrollTop":scroll-into-view&quo…

blender的下载安装和配置中文环境

引言 在3D建模和动画设计领域&#xff0c;Blender 作为一款强大且免费的开源软件&#xff0c;一直以优秀的性能和对众多技术的支持赢得了大批用户的喜爱。然而&#xff0c;对于刚接触这款软件的用户而言&#xff0c;其安装和配置过程可能会带来一定困扰&#xff0c;尤其是在设…

Maven安装(3.8.4版本)

下载maven 官方下载链接&#xff1a;Maven – Download Apache Maven 下载完成后进行解压到自己要安装的目录下 如果下载不成功可以在以下百度云盘获取(3.8.4版本) 链接: 百度网盘 请输入提取码 提取码: t9pc maven环境配置 新建系统变量&#xff1a;MAVEN_HOMEF:\maven…

opencv 30 -图像平滑处理01-均值滤波 cv2.blur()

什么是图像平滑处理? 图像平滑处理&#xff08;Image Smoothing&#xff09;是一种图像处理技术&#xff0c;旨在减少图像中的噪声、去除细节并平滑图像的过渡部分。这种处理常用于预处理图像&#xff0c;以便在后续图像处理任务中获得更好的结果。 常用的图像平滑处理方法包括…

[Linux]详解环境基础开发工具的使用

[Linux]环境基础开发工具的使用 文章目录 [Linux]环境基础开发工具的使用0. 前言1. Linux 软件包管理器 yumyum介绍yum的使用yum源 2. Linux编辑器-vimvim介绍vim基本模式底行模式下的命令汇总命令模式下的命令汇总vim简单配置 3. Linux编译器gcc/g4. Linux项目自动化构建工具-…

mysql重置和修改密码 Ubuntu系统

忘记密码要重置密码 cat /etc/mysql/debian.cnf/etc/mysql/debian.cnf这个只有Debian或者Ubuntu服务器才有&#xff0c;里面有mysql安装后自带的用户&#xff0c;作用就是重启及运行mysql服务。我们用这个用户登录来达到重置密码的操作 使用上面的那个文件中的用户名和密码登…

6.8 稀疏数组

6.8 稀疏数组 稀疏数组是一种数据结构&#xff0c;在程序中数据结构的思想&#xff0c;是非常重要的。例如 需求&#xff1a;编写五子棋游戏中&#xff0c;有存盘退出和续上盘的功能。分析问题&#xff1a;因为该二维数组的很多值是默认值0&#xff0c;因此记录了很多没有意义…

Meta押宝人工智能聊天机器人以留住用户

Meta计划发布具有人类个性的AI聊天机器人&#xff0c;这一举措旨在增强用户留存率。知情人士透露&#xff0c;该聊天机器人的原型已经在开发中&#xff0c;并有望在下个月月初推出。最终产品可以达到与用户进行正常讨论的人类水平。Meta员工将这些聊天机器人称为“personas”&a…

针对高可靠性和高性能优化的1200V硅碳化物沟道MOSFET

目录 标题&#xff1a;1200V SiC Trench-MOSFET Optimized for High Reliability and High Performance摘要信息解释研究了什么文章创新点文章的研究方法文章的结论 标题&#xff1a;1200V SiC Trench-MOSFET Optimized for High Reliability and High Performance 摘要 本文详…

【Java从入门到大牛】集合进阶下篇

&#x1f525; 本文由 程序喵正在路上 原创&#xff0c;CSDN首发&#xff01; &#x1f496; 系列专栏&#xff1a;Java从入门到大牛 &#x1f320; 首发时间&#xff1a;2023年8月2日 &#x1f98b; 欢迎关注&#x1f5b1;点赞&#x1f44d;收藏&#x1f31f;留言&#x1f43e…

windows脚本 批量删除指定文件夹、指定文件

前言 用于批量删除项目中的测试数据&#xff0c;提供用户纯净的软件。 使用说明&#xff1a; 修改file_list和folder_list对应的数据&#xff0c;来自定义删除的内容 效果图 源码 echo off chcp 65001 > nul 2>&1REM 设置文件列表&#xff0c;可以包含多个文件路…

MySQL安装详细教程!!!

安装之前&#xff0c;先卸载你之前安装过的数据库程序&#xff0c;否则会造成端口号占用的情况。 1.首先下载MySQL:MySQL :: Download MySQL Community Server(下载路径) 2.下载版本不一样&#xff0c;安装方法略有不同&#xff1b;&#xff08;版本5的安装基本一致&#xff0…

STL 之 list接口的简单使用【C++】

文章目录 push_front &&pop_frontpush_back&&pop_backinserterase迭代器begin&& endrbegin和rend front&&backsizeresizeemptyclearsortspliceuniquemergereverse ![在这里插入图片描述](https://img-blog.csdnimg.cn/717807397d8d499d840aae2…

万宾智慧排水监测系统,实现城市排水“靶向治疗”

随着城市化进程的加速&#xff0c;排水系统面临着越来越多的挑战。传统排水系统在应对城市发展带来的水资源管理和环境保护问题时&#xff0c;往往显得力不从心。近年来&#xff0c;城市内涝、河水倒灌、雨污分流不到位、河道黑臭杂乱、水体污染、井盖异常、污水溢流发臭等民生…

cmake使用笔记

vim CMakeLists.txt mkdir build cd build cmake ..创建 CMakeLists.txt&#xff0c;添加内容 cmake_minimum_required(VERSION 3.26) #工程名称 project(hello) #宏定义 add_definitions(-D宏名称) #头文件路径 include_directories(${PROJECT_SOURCE_DIR}/inc) #搜索源文件…

前端Vue入门-day07-Vuex入门

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 自定义创建项目 vuex概述 构建 vuex [多组件数据共享] 环境 创建一个空仓库 state 状态 1. 提供数据&…

Android Gradle 骚操作,将两个项目合并到一个项目中

1. 前言 在工作中&#xff0c;由于各种原因&#xff0c;导致需要将两个可单独运行的App项目&#xff0c;合并到一个git仓库里&#xff0c;且单独的App项目里还有其他Module模块。 如果只是将两个项目复制到同一个文件夹下&#xff0c;还是得单独打开各个项目&#xff0c;是很不…

基础篇:多线程所需知识:RAII接口模式对生产者和消费者封装以及多batch实现

我们先来弄一个最基础的infer类&#xff1a; class Infer{ public: bool load_model(const string &file){context_ file;return true;} void forward(){if(context_.empty()){printf("加载模型异常\n");return;}printf("使用%s进行推理\n " , contex…

图解:订单系统的设计

目录 订单系统简介 1. 订单系统在企业中的角色 2. 订单系统与各业务系统的关系 3. 订单系统上下游关系 4. 订单系统的业务架构 订单系统核心功能 1. 订单中所包含的内容信息 2. 流程引擎 订单系统的发展 最后 本文主要讲述了在传统电商企业中&#xff0c;订单系统应承…