js中浅拷贝与深拷贝_js中深拷贝和浅拷贝

文章目录

浅拷贝

浅拷贝是指源对象与拷贝对象的指针指向的内存空间是同一块空间,其中任何一个对象的改动都会对另一个对象造成影响。

深拷贝

深拷贝是指源对象与拷贝对象指针指向的内存空间不是同一块空间,相互独立,其中任何一个对象的改动都不会对另外一个对象造成影响。

在进入正题之前,不知大家对内存空间了解多少,若是无法区分栈内存堆内存,建议先去学习一下内存空间的知识:内存空间详解浅析JS中的堆内存与栈内存

一、数据类型

先来几个概念:

在js中数据类型分为基本数据类型(String、Number、Boolean、Null、Undefined、Symbol、BigInt)和引用数据类型(Object)。

基本类型值:简单的数据段,基本类型值是按值访问的,保存在栈内存中。
引用类型值:由多个值构成的对象,引用类型值是按引用访问的,引用保存在栈内存中,真实的值保存在堆内存中。

在这里插入图片描述

二、浅拷贝与深拷贝

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

仔细观察下面的示例图:
在这里插入图片描述
浅拷贝后的New List Head的指向与Original List Head的指向其实是同一个Node,因为浅拷贝复制的其实是栈内存中对象的引用,而不是保存在堆内存中真实的值,两个对象还是在共用同一个堆内存地址。而深拷贝则是创造了一个与原来一模一样的对象,指向(引用)不同,堆内存地址也不同,两个对象相互独立,互不影响。

三、浅拷贝与对象赋值

当我们把一个对象赋值给一个新的变量时,赋的其实是该对象的在栈内存中的引用地址,而不是堆内存中的数据。也就是两个对象指向的是同一个堆内存空间,无论哪个对象发生改变,其实都是改变的堆内存空间中的数据,因此,两个对象是联动的。

浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 。因此,如果其中一个对象改变了这个地址,就会影响到另一个对象。

来看两个例子加深一下印象:

对象赋值:

var obj = {
	name: '王五',
	age: 28,
	gender: ['男','女']
}
var obj2 = obj;

obj2.name = '李四';
obj2.gender[0] = '未知';

console.log('obj',obj);
console.log('obj2',obj2);

打印到控制台,不管是我们修改了obj2中的基本类型值还是引用类型值,obj中的值都被改变了,变成了相同的值。
在这里插入图片描述
浅拷贝:

// 浅拷贝辅助函数
function shallowCopy(data){
	var copy = {};
	for(var key in data){
		if (data.hasOwnProperty(key)) {
			copy[key] = data[key];
		}
	};
	return copy;
}

var obj = {
	name: '王五',
	age: 28,
	gender: ['男','女']
}
var obj3 = shallowCopy(obj);

obj3.name = '李四';
obj3.gender[0] = '未知';

console.log('obj',obj);
console.log('obj3',obj3);

来看打印结果,当对obj进行浅拷贝生成obj3时,改变obj3中的基本类型值和引用类型值,发现obj中的引用类型值发生了改变,基本类型值未发生改变。
在这里插入图片描述

由上面的例子我们可以推测出新对象对源数据的影响:

和源数据是否指向同一内存地址第一层数据为基本类型值源数据中包含子对象
对象赋值改变会使源数据一同改变改变会使源数据一同改变
浅拷贝改变不会使源数据改变改变会使源数据一同改变
深拷贝改变不会使源数据改变改变不会使源数据改变

四、浅拷贝的实现方式

1、Object.assign()

Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象,它将返回目标对象。

Object.assign()进行的是浅拷贝,拷贝的是对象属性的引用,而不是对象本身。

var source = {
	obj: { a: '哈哈哥', b: 40 },
};
var target = Object.assign({}, source);
target.obj.a = '嘿嘿哥';
target.obj.b = 50;
console.log(source);	// { obj: { a: '嘿嘿哥', b: '50' } }
console.log(target);	// { obj: { a: '嘿嘿哥', b: '50' } }

当Object.assign()对只有一层基本数据类型进行拷贝时,相当于深拷贝:

const source= { a: 1, b: 2 };
const target = Object.assign({}, source);
target.a = 111;
target.b = 222;
console.log(source);	// { a: 1, b: 2 }
console.log(target);	// { a: 111, b: 222 }

2、Array.prototype.concat()

concat() 方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。

var source = [1, 2, { name: 'CSDN', age: 21 }];
var target = source.concat();
target[0] = 100;
target[2].name = 'csdn';
console.log(source);	// [1, 2, { name: 'csdn', age: 21 }];
console.log(target);	// [100, 2, { name: 'csdn', age: 21 }];

JavaScript 和 ES6

在这个过程你会发现,有很多 JS 知识点你并不能更好的理解为什么这么设计,以及这样设计的好处是什么,这就逼着让你去学习这单个知识点的来龙去脉,去哪学?第一,书籍,我知道你不喜欢看,我最近通过刷大厂面试题整理了一份前端核心知识笔记,比较书籍更精简,一句废话都没有,这份笔记也让我通过跳槽从8k涨成20k。

JavaScript部分截图

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值