js高级特性-深拷贝和浅拷贝

js数据类型

聊深浅拷贝之前,我们得先弄清楚js的数据类型,你才能搞懂为什么要用深浅拷贝

两大数据类型

基本数据类型
string, number,boolean,null,undefine,symbol 六大基本类型
引用数据类型
Object,Array,Date,Function,RegExp

基本数据类型使用typeof可以返回其基本数据类型,但是NULL类型会返回object,因此null值表示一个空对象指针;
引用数据类型使用typeof会返回object,此时需要使用instanceof来检测引用数据类型;

<script>
	let a = 1
	let b = a
	let c = {
     a1:1}
	let d = c
	let e = [1,]
	console.log(typeof a)//number
	console.log(typeof e)//object
	console.log(e instanceof Array)//true
</script>

不同存储方式

基本类型: 基本数据类型在内存中只占固定的大小,存放在栈内存中

引用类型:引用类型的值是对象(大小不固定),保存在堆内存中

不同的赋值方式

基本类型:基本数据类型一个值赋值给另一个值,会创建一个副本,在栈内存中开辟另一处地址用来存放,两个值互相独立

引用类型:引用类型的一个值赋值给另一个值,复制的是指针,两个指针指向的同一个值,如果修改的这个值,两个变量都受影响

<script>
	let a = 1
	let b = a
	let c = {
     a1:1}
	let d = c
	b = 2
	d.a1 = 2
	console.log(a)
	console.log(b)
	console.log(c)
	console.log(d)
</script>

js高级特性-深拷贝和浅拷贝_第1张图片
从上述可以看出,基本数据类型的赋值没有什么问题,但是引用类型,就有问题,怎样才能赋值时,两个指向不同地址呢

常用方法

Object.assign()

ES6 Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。

let obj1 = {
     a:1}
	let obj2 = {
     b:2}
	let obj3 = {
     c:3}
	Object.assign(obj1,obj2,obj3)//{a:1,b:2,c:3}
	console.log(obj1)
	obj1.b = 3
	console.log(obj2){
     b:2}

Object.assign方法的第一个参数是目标对象,后面的参数都是源对象。
如果后面的属性已经存在在对象中,新的会覆盖以前的属性

如果只有一个参数,Object.assign会直接返回该参数。

let obj1 = {
     a:1}
	let obj2 = {
     b:2}
	let obj3 = {
     c:3}
	let obj4 = Object.assign(obj1)
	console.log(obj4)//1
	obj4.a = 2
	console.log(obj1)//2

JSON.stringify

将对象转换为字符串,
语法:
JSON.stringify(value [, replacer] [, space])
value:是必须要的字段。就是你输入的对象,比如数组啊,类啊等等。
replacer:这个是可选的。它又分为2种方式,一种是方法,第二种是数组。

let obj = {
     a:1,b:2}
	let b = JSON.stringify(obj)
	console.log(b)//{a:1,b:2}
var students = new Array();
	students[0] = "onepiece";
	students[1] = "naruto";
	students[2] = "bleach";
	var json = JSON.stringify(students, switchUpper);
	function switchUpper(key, value) {
     
		return value.toString().toUpperCase();
	} 

	console.log(students)//(3) ["onepiece", "naruto", "bleach"]
	console.log(json)//"ONEPIECE,NARUTO,BLEACH"

JSON.parse

将一个 JSON 字符串转换为对象。
JSON.parse(text[, reviver])
text:必需, 一个有效的 JSON 字符串。
reviver: 可选,一个转换结果的函数, 将为对象的每个成员调用此函数。

var str = '{"name":"小明","age":18}';
	let obj = JSON.parse(str)
	console.log(obj)

如果使用JSON.parse()方法来转化成json对象的数据格式的话,需要注意的是被转化的字符串里面的属性要使用引号,并且总体是单引号套双引号的方式。

深拷贝和浅拷贝

两种拷贝类型都是针对Object引用类型的,基本类型没有深浅拷贝可言

引用类型的地址存储方式
js高级特性-深拷贝和浅拷贝_第2张图片
浅拷贝
js高级特性-深拷贝和浅拷贝_第3张图片
深拷贝
js高级特性-深拷贝和浅拷贝_第4张图片

浅拷贝

浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存
1.通过使用Object.assign()实现浅拷贝

var obj = {
     
		a: 1,
		b: 2
	}
	var obj1 = Object.assign(obj);
	obj1.a = 3;
	console.log(obj.a) // 3
	console.log(obj1.a)// 3

可以看到通过这种方式拷贝,只是拷贝了指针,指向同一个堆里的对象,所以无论那个改变都会影响同一个对象

2.for···in只循环第一层

function copy (obj) {
     
		let newObj = {
     }
		for (const item in obj) {
     
			newObj[item] = obj[item]
		}
		return newObj
	}
	let obj1 = {
     a:1,b:{
     c:2}}
	let obj2 = copy(obj1)
	console.log(obj2)//{a: 1, b: {c:2}}
	obj2.a = 2
	obj2.b.c = 3
	console.log(obj1)//{a: 1, b: {c:3}}
	console.log(obj2)//{a: 2, b: {c:3}}

只对第一层属性进行了拷贝,而属性指向的对象还是指向同一个

3.直接用=赋值

let obj1 = {
     a:1}
	let obj2 = obj1
	obj2.a = 2
	console.log(obj1)//{a:2}
	console.log(obj2)//{a:2}

我们可以通过Object.assign()实现第一层深拷贝

let obj1 = {
     
		a: {
     
			b: 1
		},
		c: 2
	}
	let obj2 = Object.assign({
     }, obj1)
	obj2.a.b = 3;
	obj2.c = 3
	console.log(obj1.a.b); // 3
	console.log(obj2.a.b); // 3
	console.log(obj1.c); // 2
	console.log(obj2.c); // 3

只对第一层的对象属性进行拷贝,而对象属性所指的对象或者其他引用类型,并没有拷贝过来,所以上图c属性被拷贝,
所以当obj2修改c时不会影响obj1的c,而a属性指向一个对象,但是拷贝了第一层,对属性指向的对象没有进行拷贝,所以obj1与obj2属性a指向的还是同一个,所以当obj2改变a属性的b时,obj1的也会改变

深拷贝

深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象;
1.通过使用JSON.stringify和JSON.parse实现深拷贝
JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象;

let obj1 = {
     
		a: {
     
			b: 1
		},
		c: 2
	}
	// let obj2 = Object.assign({}, obj1)
	let obj2 = JSON.parse(JSON.stringify(obj1))
	obj2.a.b = 3;
	obj2.c = 3
	console.log(obj1.a.b); // 1
	console.log(obj2.a.b); // 3
	console.log(obj1.c); // 2
	console.log(obj2.c); // 3

可以看到不仅对第一层的属性进行拷贝,属性指的对象也就是子对象也进行了拷贝,所以obj1与obj2现在是两个独立的对象,互不影响

2.通过递归拷贝所有层级属性

function copy(obj) {
     
		let objClone = Array.isArray(obj) ? [] : {
     };
		if (obj && typeof obj === "object") {
     
			for (key in obj) {
     
				if (obj.hasOwnProperty(key)) {
     
					//判断ojb子元素是否为对象,如果是,递归复制
					if (obj[key] && typeof obj[key] === "object") {
     
						objClone[key] = copy(obj[key]);
					} else {
     
						//如果不是,简单复制
						objClone[key] = obj[key];
					}
				}
			}
		}
		return objClone;
	}

	let obj = {
      a: 1, b: {
      c: 2 } }

	let obj2 = copy(obj)

	console.log(obj){
     a: 1, b: {
     c:2}}
	console.log(obj2){
     a: 1, b: {
     c:2}}

	obj2.a = 2
	obj2.b.c = 3
	console.log(obj){
     a: 1, b: {
     c:2}}
	console.log(obj2){
     a: 2, b: {
     c:3}}

3.通过直接赋值

let obj1 = {
     
		a: 1,
		b: 2
	}
	let obj2 = {
     
		a: obj1.a,
		b: obj1.b
	}
	obj2.a = 3;
	console.log(obj1);// {a: 1, b: 2}
	console.log(obj2); //{a: 3, b: 2}

你可能感兴趣的:(javascript,javascript)