JS之深拷贝与浅拷贝

article/2025/10/12 9:05:18

一、理解

 深拷贝 与 浅拷贝

 针对于 引用类型(Object,Array,Function) 来说的

浅拷贝:在栈中分配一块新内存,拷贝需要拷贝的值,

          对简单数据类型,就是拷贝值;对复杂数据类型,就是拷贝了一份栈内存储的堆内存的地址

 深拷贝:在堆中重新分配新内存,存储新的拷贝数据;

                在栈中分配新内存,存储新数据分配的堆的地址。

标准浅拷贝:

// =
let obj1 = obj
obj.a = '88888'
console.log(obj)
console.log( obj1)

结果:

实现方式:

 浅拷贝的实现方式:

        1. 基于Object.assign()

        2. 基于for in = 直接赋值

        3. ... 原地展开

 深拷贝的三种实现方式:

      1. 递归实现(重点)

      2. JSON.stringify + JSON.parse 方法

      3. JQuery的$extend方法(了解)

 其他奇怪的api方法?可能非真正的深拷贝

     1. slice 一维数组深拷贝,多维拷贝不彻底(针对数组)

     2. Object.assign

     3. Object.create

二、一些奇怪的api的使用及测试

1.Object.assign()

Object.assign用法:

  用于将源对象的所有可枚举属性到目标对象,返回目标对象

 至少需要两个对象做参数:Object.assign(目标对象, 源对象1,...)

 只要有一个参数不是对象,就会抛出TypeError错误

 如果有同名属性,后覆盖前;只复制自身属性(也会复制Symbol值的属性),不复制不可枚举/继承属性

 可用于: 为对象添加属性或方法;克隆对象;合并多个对象;为属性指定默认值

拷贝实现:

// Object.assign 
let obj = {a: 1,b: 2,c: [1, 2, 3],d: {g:777,s: {},f: function() { console.log('f')}}
}
let obj1 = Object.assign({}, obj)
console.log(obj1)

拷贝结果:

 拷贝测试:

对第一层的测试:

obj1.a = 666 // 对第一层的基本数据类型修改=>深拷贝
obj1.c = [] // 对第一层的引用数据类型 => 深拷贝
// obj1.c[0] = '000' // 对第一层的引用数据类型 内的某一项进行修改=>浅拷贝
//obj1.d.g = 8888 //
obj1.d.s.w = '9999999' // 对内层引用数据类型进行修改(添加)=>浅拷贝
console.log(obj)
console.log( obj1)

测试结果:

 其他测试:

obj1.c[0] = '000' // 对第一层的引用数据类型 内的某一项进行修改=>浅拷贝
obj1.d.g = 8888 // 对内层基础数据类型修改 => 浅拷贝
obj1.d.s.w = '9999999' // 对内层引用数据类型某一项 进行修改(添加)=>浅拷贝
obj1.d.f = {} // 对内层引用数据类型 整体修改 => 浅拷贝
console.log(obj)
console.log( obj1)

测试结果:

小总结:

 对拷贝的第一层的基础数据类型 实现了深拷贝(修改拷贝值,不影响新值);

 对深层数据,依然是浅拷贝,修改数据值会影响原数据

注意:当整体修改第一层引用数据后,新对象的整个引用数据的指向应该是修改后的,这时再对引用数据中某一项修改时,不会影响原来的对象;但直接对于第一层引用数据类型的某一项进行修改时,还是会影响原来的对象。

2.Object.create

api用法:

 方法用于 创建一个新对象,使用现有的对象来提供新创建的对象的proto

 参数: Object.create(proto新建对象的原型对象,[添加到新创建对象的可枚举属性])

 返回值:在指定原型对象上添加新属性后的对象

拷贝:

// 3. Object.create 浅拷贝
let obj1 = Object.create(obj)
console.log(obj1) // obj1 是一个空对象,其原型为obj;obj1.__proto__是obj的浅拷贝
console.log(obj1.__proto__ === obj) // true

运行结果:

浅拷贝,新对象的原型为旧对象

obj1 是一个空对象,其原型为obj;obj1.__proto__是obj的浅拷贝

3. ES6 ...扩展运算符

代码实现:

// ES6 扩展运算符
let obj1 = { ...obj }
console.log(obj1)

测试结果同Object.assign

4.slice+concat实现拷贝(针对数组)

slice:

实现及测试:

// 针对数组
let arr = ['a', 'b', 'c', {d:4}]// slice
let arr1 = arr.slice(0)
// console.log(arr)
// console.log(arr1)arr1[0] = '1'
arr1[3].d = '777'
console.log(arr)
console.log(arr1)

运行结果:

 可见,slice 对于数组中的基础数据类型,能够实现深拷贝,对于引用数据类型,无法实现深拷贝。

concat:

// concat
let arr1 = arr.concat()// console.log(arr)
// console.log(arr1)

测试结果与slice相同。

三、实现深拷贝的三种方式

1. JSON.stringify + JSON.parse

拷贝实现:

let obj = {a: 1,b: 2,c: [1, 2, 3],d: {g:777,s: {w:'www'},f: function() { console.log('f')}},e: undefined,p: NaN,date:new Date()
}
// JSON.stringify + JSON.parse 方法
let obj1 = JSON.parse(JSON.stringify(obj))
console.log(obj)
console.log(obj1)

结果截图:

可见,拷贝对象无函数f、无undefined属性e,即该方法无法实现对函数、对undefined值的拷贝 ;

经测试,为深拷贝。

该方法存在的问题:

1.对象中有时间类型时,序列化后会变成字符串类型;

2.对象中有function、undefined类型的数据,会直接丢失;

3.对象中有NaN、Infinity、-Infinity时,序列化后会显示null;

4.对象循环引用时,会报错。

2.JQuery中的$.extend方法可以实现深拷贝(知道)

3.递归实现深拷贝(待升级完善版)

深拷贝的简单递归实现:

let obj = {a: 1,b: 2,c: [1, 2, 3],d: {g:777,s: {w:'www'},f: function() { console.log('f')}},e: undefined,p: NaN,date:new Date()
}// 递归实现深拷贝--简单版()
function deepClone(obj) {let newObj = null// if (obj === null) return obj//???if (typeof obj == 'undefined') return undefinedif (typeof obj === 'function') return obj//浅拷贝函数?if (obj.constructor == Date) return new Date(obj)if(obj.constructor == RegExp) return new RegExp(obj)if (typeof obj == 'object') {newObj = obj instanceof Array ? [] : {}for (let key in obj) {if (obj.hasOwnProperty(key)) {newObj[key] = deepClone(obj[key])}}} else {newObj = obj}return newObj
}let obj1 = deepClone(obj)
console.log(obj)
console.log(obj1)

运行截图:

复杂版:

// 深拷贝 复杂版?
function checkType(target) {console.log(Object.prototype.toString.call(target).slice(8,-1))return Object.prototype.toString.call(target).slice(8,-1)
}function deepClone2(data) {const obj = checkType(data) === 'Array' ? [] : {}let arr = ['Object','Array']if (arr.includes(checkType(data))) {for (let key in data) {let value = data[key]//value为简单类型,直接赋值if (!arr.includes(checkType(value))) {obj[key] = value} else {// 定义一个映射,初始化时,将data本身加入映射中const map = new WeakMap()// 如果拷贝的是复杂数据类型第一次拷贝后存入map// 第二次再遇到该值时,直接赋值为null,结束递归map.set(data, true)if (map.has(value)) {obj[key] = null} else {map.set(value, true);obj[key] = deepClone2(value)}}}} else {return data}return obj
}let obj1 = deepClone2(obj)
console.log(obj)
console.log(obj1)

结果:

 


http://chatgpt.dhexx.cn/article/uDpe1W7p.shtml

相关文章

lua踩坑之浅拷贝与深拷贝

文章目录 一、前言二、浅拷贝和深拷贝三、浅拷贝1.拷贝对象为string、number、boolean等基础类型时2.拷贝对象的类型为table类型时 三、深拷贝 一、前言 先来说说,为什么突然谈及到浅拷贝和深拷贝这个问题。因为时间紧任务重,lua零基础参与项目研发&…

解决浅拷贝的五种方式

浅拷贝和深拷贝以及值类型、引用类型概念理解请移步 认识javascript值类型,引用类型及浅拷贝与深拷贝的关系小白gis每周更新与WebGIS设计相关的文章教程,通过在线示例以及demo的方式,介绍Arcgis API、开源gis API的使用方法,帮助学…

iOS-深拷贝和浅拷贝

一、深拷贝(Deep Copy) 和 浅拷贝(Shallow Copy) 1、深拷贝(Deep Copy):内容拷贝,拷贝数据到一块新内存区域,指针指向拷贝的数据区 (另外创造一个一模一样的对象,新对象跟原对象不共享内存&am…

实现浅拷贝

浅拷贝是指,一个新的对象对原始对象的属性值进行精确地拷贝,如果拷贝的是基本数据类型,拷贝的就是基本数据类型的值,如果是引用数据类型,拷贝的就是内存地址。如果其中一个对象的引用内存地址发生改变,另一…

浅拷贝

图片转自js 深拷贝 vs 浅拷贝 我们平常说的深拷贝和浅拷贝都是基于对诸如 Object 和 Array 等引用数据类型的拷贝。对于基本数据而言,拷贝为某个值的赋值。 在说拷贝之前,我们先复习一下什么是基本数据类型和引用类型。 基本数据类型 JavaScript 中基…

深浅拷贝以及解决浅拷贝(以string浅拷贝为例)

一、什么是浅拷贝 在类和对象的时候,其中编译器生成的默认拷贝构造函数中,内置类型是按照字节方式直接拷贝的,而自定义类型是调用其拷贝构造函数完成拷贝的。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅…

ctf之培根密码

根据特征怀疑是培根密码 flag{AAAABAAAAAAAABAABBBAABBABABAAABAABAAAABBAABAAABABBABAAAAAABAABAAAABBBABABAABAABA} 直接在线解密 https://tool.bugku.com/peigen/ flag{BACONISDELICIOUS}

培根密码加解密

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴! 0x00 介绍 培根密码实际上就是一种替换密…

培根密码解密脚本

官方吐槽:疫情复发难受,什么时候是个头 #!/usr/bin/env python3 # -*- coding:utf-8 -*- #Author:later_future import string miweninput("请输入密文:") count0 msg"" flag"" #培根加密百度百科…

攻防世界crypto部分sherlock的writeup,原来不是培根密码。

下载附件后,发现是一个很大的文本,搜了下flag没啥收获。 1、后来看到下面这个 2、明显的故意大写,难道是培根密码?这就有思路了,将大写过滤出来: cat f590c0f99c014b01a5ab8b611b46c57c.txt | grep -Eo […

培根密码加解密(Python)

原理 加密时,明文中的每个字母会根据下面转换成5个字母; 解密时,密文中的每5个字母为一组转换成对应的1个字母; Python代码如下: CODE_TABLE { #培根字典aaaaa:a,aaaab:b,aaaba:c,aaabb:d,aabaa:e,aabab:f,aabba:…

CTF密码学-加解密总结

零基础学黑客,搜索公众号:白帽子左一密码学基本简介 密码学(在西欧语文中,源于希腊语krypts“隐藏的”,和grphein“书写”)是研究如何隐密地传递信息的学科。 在现代特别指对信息以及其传输的数学性研究&…

密码及编码

1. 密码 古典密码学 凯撒密码(Caeser):位移密码 特殊形式(加解密相同,因为26个字母是循环的):ROT13 栅栏密码:分组密码。 弗吉尼亚 现代密码学 对称加密算法:使用加密用过的秘钥及相同算法的…

CTF-密码学-培根密码

题目:bacon bAcon iS a MEaT prodUcT prePared frOm a pig and UsuALLy cUReD. 读题:翻译过来意思是培根 审题:联想到培根密码 解题:培根密码就是大写变A小写变B import string timu"bAcon iS a MEaT prodUcT prePared frOm…

【无标题】简单的培根密码解密

第一题 题目AABBBAABAAABABAABABAABBAB BABAAABBABBAAAAAAABB 此题由大写字母AB组成,不难看出这可以用培根密码转换器进行解密得出flag 解密得出flag{HELLO WORD}

CTF-Show密码学【摩斯码、培根密码】

萌新 密码33 一、题目信息 题目名称:我想吃培根题目描述:-- — .-. … . …–.- … … …–.- -.-. — — .-… …–.- -… …- - …–.- -… .- -.-. — -. …–.- … … …–.- -.-. — — .-… . .-. …–.- – – -… -… – -… – -… – – – -…

CTF-培根密码

CTF学习上的一些疑点和解疑 主题:培根密码的随意性 反正我是觉得挺离谱的 序章 CTF学习上的一些疑点和解疑前言:培根小贴士一、培根密码是什么?二、解答1.题目2.解密顺序 总结还没听懂的我给大家展现一些例子: 前言:…

密码学笔记——培根密码

培根密码,培根所用的密码是一种本质上用二进制数设计的,没有用通常的0和1来表示,而是采用a和b 一、培根密码加密方式 第一种方式: A aaaaa B aaaab C aaaba D aaabb E aabaa F aabab G aabba H aabbb I abaaa J abaab K ababa L ababb M abbaa N abbab O abbba P abb…

培根密码(Bacon)——python解密

简介 培根密码,又名倍康尼密码(英语:Bacon’s cipher)是由法兰西斯培根发明的一种隐写术。 特点: 培根密码本质上是将二进制信息通过样式的区别,加在了正常书写之上。培根密码所包含的信息可以和用于承载…

CTF-bacon(培根密码)

一、题目 培根密码实际上就是一种替换密码,根据所给表一一对应转换即可加密解密 。它的特殊之处在于:可以通过不明显的特征来隐藏密码信息,比如大小写、正斜体等,只要两个不同的属性,密码即可隐藏。 二、解题思路 …