理解JavaScript中的深拷贝与浅拷贝

一、基本类型与引用类型的区别

1、基本类型与引用类型在存储上的区别

现在只看栈区和堆区,也假定只是局部变量。
在这里插入图片描述

函数test()被调用时:
1、定义局部变量age,由于age是局部变量,所以在栈中申请内存空间,起名age,给age赋值为25,为基本类型,所以值直接存储在栈中。
2、定义局部变量arr,arr是局部变量,在栈中申请空间,但是由于给arr赋的值不是基本类型,而是引用类型(new出来的),所以需要先在堆中申请空间存放数据18,23,99,再把堆中的地址赋给arr,所以在栈中arr里存方法的是指向堆区的指针。

2、基本类型和引用类型

  • 基本类型:就是值类型,即在变量所对应的内存区域存储的是值,如:上面的age变量内存存储的就是值25。
  • 引用类型:就是地址类型,存放指向堆中的指针。上面的arr就是引用类型,arr对应的内存中存储着地址,真正的数据存储在地址对应的内存区域里。

二、基本类型和引用类型在赋值时内存的变化

可以理解为,赋值就是在拷贝。

1、基本类型

在这里插入图片描述

2、引用类型

在这里插入图片描述
此时,如果在声明一个arr1 = arr,将arr[0]的值修改后,arr1[0]的值也会发生变化。
在这里插入图片描述
内存会发生如下变化:
在这里插入图片描述
arr和arr1指向的是相同的内存地址。

三、深拷贝和浅拷贝

所谓拷贝,就是赋值,把一个变量赋给另一个变量,就是把变量的内容进行拷贝。把一个对象的值赋给另一个对象,就是把这个对象拷贝一份。

1、基本类型没有问题

因为基本数据类型赋值时,赋的是数据(所以不存在深拷贝和浅拷贝的问题)。

// 例如:
var x = 100;
var y = x;  // 此时x和y都是100,如果改变y的值,x的值不会改变。

2、引用类型有问题

引用类型赋值时,赋的值是地址(就是引用类型变量在栈内存中保存的内容)。

// 例如:
var arr = new Array(18, 23, 99);
var arr1 = arr; // 这就是一个简单的浅拷贝

如果改变arr1[0] = 33时,arr[0]的值也是33(上面已经测试过了)。原因就是arr和arr1引用了同一块内存区域。这是最简单的浅拷贝,只是把arr的地址拷贝了一份给arr1,并没有把arr的数据也拷贝一份,拷贝的深度不够

3、用json对象的方式来演示深拷贝和浅拷贝

(1)定义一个json对象(对象的属性也是对象)

var obj = {
	id: "909",
	name: "小王",
	color: new Array("blue", "pink", "yellow") // 引用类型
}

(2)把obj对象复制一份

  • (一)浅拷贝
var obj1 = {};
for(let key in obj) {
	obj1[key] = obj[key];
}
obj1.color[0] = "green";
console.log(obj);
console.log(obj1);

在这里插入图片描述
内存:
原始obj对象:
在这里插入图片描述
浅拷贝:
在这里插入图片描述

  • (二)深拷贝(初步)
var obj = {
	id: "909",
	name: "小王",
	color: new Array("blue", "pink", "yellow") // 引用类型
}
var obj1 = {};
for(let key in obj) {
    if(typeof obj[key] == 'object') {
        obj1[key] = [];
        for(let i in obj[key]) {
            obj1[key][i] = obj[key][i];
        }
    } else {
        obj1[key] = obj[key];
    }
}
obj1.color[1] = "black";
console.log(obj);
console.log(obj1);

在这里插入图片描述
内存:
在这里插入图片描述

  • (三)深拷贝(最终)
3.1 如果属性都是json对象,那么采用递归的方式
var p = {
    "id": "007",
    "name": "Sean",
    "wife": {
        "id": "008",
        "name": "Yibo",
        "address": {
            "city": "beijing",
            "area": "海淀区"
        }
    }
}
function copyDeep(obj) {
    let newObj = {};
    for(let key in obj) {
        if(typeof obj[key] == 'object') { // 如果是引用类型,就递归
            newObj[key] = copyDeep(obj[key]);
        } else { // 基本类型,则直接赋值
            newObj[key] = obj[key];
        }
    }
    return newObj;
}
let newP = copyDeep(p);
newP.wife.name = "bobo";
newP.wife.address.city = "shanghai";
console.log(newP);
console.log(p);

在这里插入图片描述

3.2 如果属性是数组等非键值对的对象
// 给数组对象增加一个方法,用来复制自己
Array.prototype.copyself = function() {
    let arr = new Array();
    for(let i in this) {
        arr[i] = this[i];
    }
    return arr;
}
var aObj = {
    id: "111",
    name: "Sean",
    like: new Array("apple", "banana", "lemon")
}
function copyObj(obj) {
    let newObj = {};
    for(let key in obj) {
        if(typeof obj[key] == 'object') {
            newObj[key] = obj[key].copyself();
        } else {
            newObj[key] = obj[key];
        }
    }
    return newObj;
}
var newVal = copyObj(aObj);
newVal.like[0] = "orange";
console.log(aObj);
console.log(newVal);

在这里插入图片描述

参考链接:https://blog.csdn.net/jiang7701037/article/details/98738487

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值