【手写代码】深拷贝和浅拷贝

本文介绍了JavaScript中深拷贝和浅拷贝的概念,通过实例解释了浅拷贝包括最简单的赋值拷贝、数组的concat方法和对象的Object.assign方法。同时,提到了使用JSON.parse(JSON.stringify())方法实现深拷贝的限制,如无法拷贝null、undefined、function。最后,文章指出实现深拷贝的关键在于处理引用类型,需要递归遍历确保所有数据都是基本类型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、定义

二、举例🌰

1. 最简单的浅拷贝

2. 数组的浅拷贝( new_arr.concat(arr) )

3. 对象的浅拷贝( Object.assign(new_obj, obj) )

4. 使用json实现深拷贝(以数组为例)

总结:常用的拷贝技术

三、手写深拷贝


一、定义

拷贝:就是赋值,把一个变量赋值给另一个变量,对变量的内容进行拷贝。

了解深拷贝和浅拷贝之前需要对基本数据类型和引用数据类型的内存上存储(栈/堆)的区别有清楚地认识,深拷贝和浅拷贝是针对于引用数据类型。

浅拷贝:拷贝后的数据会影响原数据

深拷贝:产生了新的数据,而不是对原数据的引用

判断依据:数据存放是对象在栈内存地址的引用还是对象的引用

二、举例🌰

1. 最简单的浅拷贝

//地址的拷贝,不产生新的数据
var arr = [1,2,4];
Var new_arr = arr;
new_arr[0] = '改';
console.log(arr, new_arr);  

2. 数组的浅拷贝( new_arr.concat(arr) )

//只拷贝一层(深度不够)
let arr = ['chailo',2,null,undefined,function f() {},[5],[6],{obj: 'obj'}];
let new_arr = [].concat(arr)
new_arr[5] = ['改'];
new_arr[6][0] = '改';
new_arr[7].obj = '改';
console.log(arr,new_arr);

3. 对象的浅拷贝( Object.assign(new_obj, obj) )

//只拷贝一层(深度不够)
let obj = {
    name: 'chailo',
    age: 20,
    n: null,
    u: undefined,
    f() { return 1},
    arr1: [1],
    arr2: [[2]],
    obj: {name: 'obj'}
}
// string number null undefined function object object 
let new_obj = {};
Object.assign(new_obj, obj);
new_obj.arr1 = ['改'];
new_obj.arr2[0] = ['改'];
new_obj.obj.name = '改';
console.log(obj, new_obj);

4. 使用json实现深拷贝(以数组为例)

let arr = ['chailo',2,null,undefined,function f() {},[5],[6],{obj: 'obj'}];
let new_arr = JSON.parse(JSON.stringify(arr));
new_arr[5] = ['改'];
new_arr[6][0] = '改';
new_arr[7].obj = '改';
console.log(arr,new_arr);

​  

可以实现深拷贝,但是需要注意⚠

JSON.parse(JSON.stringify(obj)) . 对于null、undefined、function的拷贝结果都是null!!!

总结:常用的拷贝技术

  1. 数组浅拷贝:arr.concat()

  2. 数组浅拷贝:arr.slice()

  3. 对象浅拷贝:Object.assign({},a)

  4. 使用扩展运算符进行对象的浅拷贝:obj1 = {...obj}

  5. 使用扩展运算符进行数组的浅拷贝:arr1 = {...arr}

  6. 数组或对象的深拷贝:JSON.parse(JSON.stringify(arr/obj))

三、手写深拷贝

核心思想:克隆的数据不能有引用类型。如果有,继续遍历挖掘直到每次拷贝都是基本数据类型。

function cloneUtil(target){
    var result;
    //判断克隆的目标是对象还是数组👇
    if(getType(target)==='Object'){
        result={};        
    }else if(getType(target)==='Array'){
        result=[];        
    }else{                                  //基本数据类型
        return target;
    }
    //遍历目标数据
    for(var i in target){
        //收集个体数据
        var item=target[i];
        //判断 拷贝的数据不能有引用类型,一旦有引用类型继续拆解克隆
        if(getType(item)==='Object'||getType(item)==='Array'){
            result[i]=cloneUtil(item);
        }else{//拷贝的过程
            result[i]=item;    
        }   
    }
}
//补充💬:判断克隆的目标是对象还是数组👆
//方法1:instanceof
//方法2:toString
var arr=[1,2,3];
var obj={
    name:'chailo'
}
console.log(arr.toString());    //1,2,3
console.log(obj.toString());    //[object Object]
Objext.prototype.toString.call(arr);    //使数组调用object.prototype中的toString
console.log(Objext.prototype.toString.call(arr));   //[object Array]
//封装方法
function getType(target){
    return Object.prototype.toString.call(target).slice(8,-1);
}

参考文章🚗

面试题:深拷贝和浅拷贝(超级详细,有内存图)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值