javascript的浅拷贝与深拷贝

一、数据类型

JavaScript有lia两种数据类型:

1.基本数据类型:Number、String、Undefined、Null、Boolean、Symbol。这六种数据类型数据段简单,大小可以确定,存放在栈中,是直接按值存放的,也可以直接访问。

2.引用类型:如对象、数组等。这些对象的大小不一定,是存放在堆中的,其在栈中的值只是一个指向堆的指针。

 

二、引发的问题

1.复制基本类型数据时,栈的值可以直接引用。

2.复制引用类型数据时,栈的值只是一个指向堆的指针,当改变其中一方的值时,另外一方的值也会跟着改变。

如下:

		let a = 'hi';//基本数据类型,在栈中的值可以直接引用
		let b = [1, 2, 3];//数组,在栈中的值是指向堆的指针
		let c = a;//复制 a
		let d = b;//复制 b

		console.log('第一次的a: ', a)
		console.log('第一次的b: ', b)
		console.log('第一次的c: ', c)
		console.log('第一次的d: ', d)

		c = 'hi-hi';//复制基本类型的值,修改不会影响其他变量。
		d.push(4); //复制引用类型的值,修改时都有影响

		console.log('--------------')
		console.log('第二次的a: ', a)
		console.log('第二次的b: ', b)
		console.log('第二次的c: ', c)
		console.log('第二次的d: ', d)

可以看到,d是复制b(引用类型),当向d中插入数据时,b的数据也是变化的。因为b只是复制了d在栈中指向堆的指针,也就是b和d是共用一个堆的,不管哪一方修改,两者的值都是同步改变。

三、浅拷贝

通过上面可以得出,如果我们拷贝一个引用类型,我们两者互不影响,那就应该新开辟一个堆来存放,而不是只拷贝在栈中指向堆的指针。

浅拷贝,网上很多都说是只拷贝一层,意思大概如下:

        let e = {
			name: '浅拷贝',
			arrys: [11,22,33]
		}
		function copySimple (obj){
			let newObj = {}

			newObj.name = obj.name;
			newObj.arrys = obj.arrys;
			return newObj;
		}

		let f = copySimple(e);
		console.log('--------------')
		console.log('第一次浅拷贝的e: ', e)
		console.log('第一次浅拷贝的f: ', f)

		f.name = '浅拷贝,修改';
		f.arrys.push(44);
		console.log('--------------')
		console.log('第二次浅拷贝的e: ', e)
		console.log('第二次浅拷贝的f: ', f)

对象e中存在一个数组值,我们的函数 copySimple 通过获取e对象的每一个值,返回一个新的对象,这样子我们拷贝的就不是edui'对象在zha栈中指向堆的指针,而是直接到堆中找相应的值。这里有两种qing情况:

像e.name 的值是一个String(基本数据类型),其值可以直接引用。而像e.arras 的值是一个数组(引用类型),此时拷贝出来的arrys值又是一个指向堆的指针。所以当我们在 f.arrys 中插入一个值时,照样会改变 e 对象中 arrys的值。这就是浅拷贝,没有把对象的对象再进行遍历到成为基本类型就进行赋值。

四、深拷贝

深拷贝网上很多说是多层拷贝,就是通过将对象中的每一个对象值进行遍历,使其成为基本数据类型再进行拷贝,这样拷贝出来的对象的值就完全是存放在另一个堆中,拷贝对象的数据变化也不会对其产生影响。如下:


		let g = {
			name: '深拷贝',
			arrys: [11,22,33]
		}

		function coypDeep(obj){
			let newObj = {}
			
			if(obj.name){
				newObj.name = obj.name;
			}

			if( obj.arrys ){
				let newArrys = [];
				
				for(let val of obj.arrys){
				    newArrys.push(val)
				}

				newObj.arrys = newArrys;
			}

			return newObj;
		}

		let h = coypDeep(g);
		console.log('--------------')
		console.log('第一次深拷贝的g: ', g)
		console.log('第一次深拷贝的h: ', h)

		h.name = '深拷贝,修改';
		h.arrys.push(44);
		console.log('--------------')
		console.log('第二次深拷贝的g: ', g)
		console.log('第二次深拷贝的h: ', h)

coypDeep函数将 g.arrys 数组遍历了一遍,成为基本数据类型。当我们再次改变 复制出来的 h,arrys 的值时,原来的对象 g 中的 arrys 值也不会改变。

五、实现深拷贝几种方法

1.通过 JSON.stringify()将对象字符串化,再进行拷贝。

2.[...obj],通过es6扩展运算符将对象都列成基本数据类型再赋值。

3.Array.from()可以将数组重新zhu转成数组再赋值。

......

猜你喜欢

转载自blog.csdn.net/sinat_35538827/article/details/85849204