首页 > 其他分享 >浅拷贝、深拷贝

浅拷贝、深拷贝

时间:2023-08-25 10:36:07浏览次数:43  
标签:console log let key obj 拷贝

理解

1、浅拷贝:是对目标的简单复制。只能复制目标对象的值引用,并没有重新开辟新的存储空间,这导致只要其中一方值被修改,另一个也跟着被修改了值。
2、深拷贝:内存地址是自主分配的,两个数据指向了不同的地址,数据元素发生改变时不会相互影响。
不过,拷贝一般只针对Array和Object

先来说说在JavaScript中,存在浅拷贝的现象

1、赋值
var arr = [1, 2,3];
var arr2;

//把arr赋值给arr2
arr2 = arr;
console.log("arr2:", arr2);  // 输出: [1, 2,3]
console.log("---改变arr2中数组元素的值后---");
arr2[0] = 3;
console.log("arr:", arr);   // 输出: [3, 2,3]
console.log("arr2:", arr2); // 输出: [3, 2,3]


2、拓展运算符
const t = [[1,[5,[6]]], 2, "3"]
const s = [...t]
t.push(9)
t[0][1][1] = 9
console.log('t===',t)  // t=== [ [ 1, [ 5, 9 ] ], 2, '3', 9 ]
console.log('s===',s)  // s=== [ [ 1, [ 5, 9 ] ], 2, '3' ]
console.log(s[0][1][1])  // 9
//这个例子 可以看出,当数组为三维数组时,拓展运算符并不能隔离变量 t 的变化

常用的简易浅拷贝方案

1:
 Object.assign(目标对象,需要拷贝的对象,需要拷贝的对象2,...)  
//如:
let a = {a:1,b:2,c:()=>{}}
let d = Object.assign({},a,{u:8})
// 输出:{a: 1, b: 2, uu: 8, c: ƒ},修改a或者d内的属性不会对对方产生影响

2:JSON.Parse(JSON.stringify(obj))  

【此方法比深拷贝浅,比浅拷贝深。原因是除了对象是函数类型,对于其他深度的基本类型子对象都满足深拷贝定义。
使用时的注意事项:https://www.cnblogs.com/fanqshun/p/16928676.html】

let f = JSON.parse(JSON.stringify(a))
 // 输出,{a: 1, b: 2},  注意:此处,原来对象a 
//->中的子对象c被噶掉了,所以此方法使用的时候需要注意这一点
JSON.parse(JSON.stringify({h:[1,2],p:90})) 
//输出:{h: Array(2), p: 90},数组类型对象不被影响  
//----------------一下方式仅适用于数组----------------------------
3.concat()
//用于连接两个或多个数组。该方法不会改变现有数组,仅仅只会返回被连接数组的一个副本。只有在数组元素是一维的时候,是深拷贝,一维以上是对值的引用 
let  a = [1,2,3]
let b = a.concat()
b[1] = 999
console.log(b) // 输出:[1,999,3]

4. slice()
//1)没有参数的时候,是拷贝数组
//2)一个参数的时候,拷贝从起始位置到数组末尾的元素
//3)两个参数的时候,拷贝从起始位置到 结束位置的元素(不包含结束位置的元素,含头不含尾)
//一维数组元素是深拷贝,数组元素二维以上是值的引用
c = a.slice();
b[2] = 100
console.log(c) // 输出:[1,2,100],并不影响a、b的值

let b = [[[3],12],1,3]
let c = b.slice();
c[0][0]=90
console.log(c) // 输出:[[90,12],1,3]
console.log(b) // 输出:[[90,12],1,3] ,修改后被影响

手写一个浅拷贝

 const shallowCopy = (obj) => {
    if (obj == null) return obj; // 不是对象时返回自身
    if (obj instanceof Date) return new Date(obj);
    if (obj instanceof RegExp) return new RegExp(obj);
    // 可能是对象或者普通的值  如果是函数的话是不需要深拷贝
    let target = Object.prototype.toString.call(obj) == '[object Array]' ? [] : {}
    if (obj.constructor === Object) {
        for (let key in obj) {
            if (Object.prototype.hasOwnProperty.call(obj, key)) {
                target[key] = obj[key]
            }
        }
    }
    if (obj.constructor === Array) {
        target = [...obj]
    }

    return target

}
var a = {
    a: 1,
    b: {
        b: 2
    },
    c: [1, 2, 3, [4, 5]],
    op: () => { }
}
const v = shallowCopy(a)
v.c[3] = [4, 5, 6]
v.op = [4, 5, 6]
console.log('v===', v);  
//v=== { a: 1, b: { b: 2 }, c: [ 1, 2, 3, [ 4, 5, 6 ] ], op: [ 4, 5, 6 ] }
console.log('a===', a);  
//a=== { a: 1, b: { b: 2 }, c: [ 1, 2, 3, [ 4, 5, 6 ] ], op: [Function: op] }

由上可以看出,当使用shallowCopy 拷贝目标对象内的属性值层级过深,修改新拷贝的对象会影响原目标的值

简易深拷贝

const deepCopy = (obj) => {
    if (obj == null) return obj; // 不是对象时返回自身
    if (obj instanceof Date) return new Date(obj);
    if (obj instanceof RegExp) return new RegExp(obj);
    if(typeof obj !== 'object') return obj
    // 可能是对象或者普通的值  如果是函数的话是不需要深拷贝
    let target = (obj.constructor) == Array ? [] : {}

    for (let key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, key)) {
            if (typeof obj[key] == 'object') {//引用类型
                target[key] = deepCopy(obj[key])
            } else {// 基本类型走这里

                target[key] = obj[key]
            }
        }
    }


    return target

}
var a = {
    a: 1,
    b: {
        b: 2
    },
    c: [1, 2, [4,5]],
    op: () => { }
}
const v = deepCopy(a)
v.c[2] = 200
console.log('v===', v);
console.log('a===', a);


由上可以看出此方法拷贝出来的新对象就算被修改也不会影响原对象值

标签:console,log,let,key,obj,拷贝
From: https://www.cnblogs.com/nyy-neal/p/17654916.html

相关文章

  • .bat执行拷贝和写入文件
    echooff::设置utf-8编码chcp65001::先删除web_out目录下的所有文件及子目录cd../web_outdel/Q/F/S*&rd/S/Q.::进入源代码路径中cd../source_code::执行打包命令callnpmrunbuild::进入dist文件中cddist::执行拷贝命令robocopy...\..\web_ou......
  • C++拷贝构造、赋值函数
    拷贝构造拷贝构造就是一种特殊版本的构造函数,格式:类名(const类名&that){    //执行给每个成员变量进行赋值  }什么时候会调用拷贝构造:当使用旧对象(已new的)给新对象(新new的)初始化时,会自动调用拷贝构造    Testt1;//调用无参构造Testt2=t1......
  • Java的深拷贝与浅拷贝的区别
    1、二者的区别浅拷贝:在拷贝一个对象时,对对象的基本数据类型的成员变量进行拷贝,但对引用类型的成员变量只进行引用的传递,并没有创建一个新的对象,当对引用类型的内容修改会影响被拷贝的对象。深拷贝:在拷贝一个对象时,除了对基本数据类型的成员变量进行拷贝,对引用类型的成员变量进行......
  • C#深拷贝
    最近在做winform项目,遇到页面上有同一个数据源的两个ComboBox,此时操作一个ComboBox,会影响到另一个ComboBox,究其原因,是因为数据源是引用类型,值栈引堆,虽然是不同的ComboBox,但是指针指向同一个内存地址,所以操作一个变量会影响到另一个,为解决这个问题,考虑使用深拷贝的方式。下边是我......
  • C# 深拷贝和浅拷贝的区别
    含义:深拷贝和浅拷贝最根本的区别在于是否真正获取一个对象的复制实体,而不是引用。假设B复制了A,修改A的时候,看B是否发生变化:如果B跟着也变了,说明是浅拷贝,拿人手短!(修改堆内存中的同一个值)如果B没有改变,说明是深拷贝,自食其力!(修改堆内存中的不同的值)浅拷贝(shallowCopy)只复制了原......
  • Linux常用命令_拷贝移动、打包压缩、文本编辑命令(cp、mv、tar、vim)
                ......
  • c++ 丢失笔记 [运算符重载、this指针、复制与拷贝构造、生存周期、箭头操作符]
    运算符重载、this指针、复制与拷贝构造、生存周期、箭头操作符有一部分是学校的OJ里做题需要就提前学了,然后没记笔记,有一部分是笔记丢了。不打算补这些笔记。不过还是在这里mark一下++运算符的重载。因为++运算符可以前置也可以后置,所以这里需要注意一下,如果是后置++,需要一个in......
  • 浅拷贝与深拷贝
    From: B座17楼 2022-06-2310:12 发表于重庆--------------------------------------------------------------copy() 深浅的区别doesn’talwaysreallycopy 并不总是复制要复制一个list或dict,可以写 my_list.copy() 或 my_dict.copy()到此为止,一切顺利。但是,如......
  • DTO、对象拷贝——多表查、修改、添加
    问题介绍一:一个分页查询方法,前端页面需要展示菜品信息(dish表),和菜品类型id信息(categoryId),但是菜品类型类中的菜品分类属性字段,菜品表中没有,所以使用DTO类,将两类信息保存到一个DTO类中。1、DishDto类其中该类继承Dish,所以有Dish类中的所有字段属性,本身自带categoryName属性与List......
  • 浅拷贝和深拷贝
    前言面试的时候经常会问到深拷贝和浅拷贝,那么python的深拷贝和浅拷贝有什么区别呢?思考题先来看2个简单的案例,对元素a/aa重新赋值一个新的变量b/bb后,改变原来a/aa的值,看会不会影响新的变量b/bb的值#1.stra="hello"b=aa="world"print('a:{}'.format(a))......