浅谈赋值、深浅拷贝

js分基本数据类型和引用数据类型

基本数据类型:String, Number, Boolean, Symbol, Undefined, Null.

引用数据类型:Object、Array、Function

基本数据类型数据存放在栈中,引用类型数据存放在堆中

 

浅谈赋值、深浅拷贝_第1张图片

先来弄清楚浅拷贝与赋值之前的区别:

赋值:obj保存了一个对象的实例,这个值被赋值到 obj2中。赋值操作完成后,两个变量实际引用的是同一个对象,改变了其中一个,会影响另外一个值。

什么是浅拷贝?如果是对象类型,则只拷贝一层,如果对象的属性又是一个对象,那么此时拷贝的就是此属性的引用。

看下面这个例子

let obj = {
	str : 'abc',
	num : 123,
	arr : [1,2,3],
};

let obj2 = obj;
console.log(obj == obj2)//true

let obj3 = shallowCopy(obj);
function shallowCopy(source){
	var target = {};
	for (var key in source){
		if (Object.prototype.hasOwnProperty.call(source,key)){
			target[key] = source[key];
		}
	}
	return target;
}

obj.arr[0] = [1,1,1];
obj.str = 'cde';
obj2.arr[1] = [2,2,2]
obj3.num = 3;
obj3.arr[2] = [3,3,3]
console.log(obj);
/*输出
{
  str: 'cde',
  num: 123,
  arr: [ [ 1, 1, 1 ], [ 2, 2, 2 ], [ 3, 3, 3 ] ]
}
*/
console.log(obj2);
/*输出
{
  str: 'cde',
  num: 123,
  arr: [ [ 1, 1, 1 ], [ 2, 2, 2 ], [ 3, 3, 3 ] ]
}
*/
console.log(obj3);
/*输出
{ str: 'abc', num: 3, arr: [ [ 1, 1, 1 ], [ 2, 2, 2 ], [ 3, 3, 3 ] ] }
*/

可以看到修改objstr 属性不会影响 obj3,但是修改 obj3的 arr属性(是个对象)的 arr[2],就会影响 obj的arr[2],因为arr是个对象。

浅拷贝和深拷贝的区别:

浅拷贝:“授人以鱼”,传值,依赖之前的对象,复制的结果是两个对象指向同一个地址,修改其中一个对象的属性,则另一个对象的属性也会改变

深拷贝:“授人以渔”,传址,掌握方法,翅膀过硬,自食其力,开辟新的内存,两个对象对应两个不同的地址,修改其中一个对象的属性,不会改变另一个对象的属性。

使用下面这些函数得到的都是浅拷贝:

  • Object.assign

  • Array.prototype.slice()Array.prototype.concat()

  • 使用拓展运算符实现的复制

用concat、slice实现浅拷贝

var arr = ['one',1,true];

//用concat实现浅拷贝
//var arr2 = arr.concat();
//用slice实现浅拷贝
var arr2 = arr.slice();

arr2[0] = 'two';
console.log(arr);//[ 'one', 1, true ]
console.log(arr2);//[ 'two', 1, true ]

如果数组嵌套了对象或者数组的话

var arr = [{one: 1},[1,2,3]];

//用concat实现浅拷贝
//var arr2 = arr.concat();
//用slice实现浅拷贝
var arr2 = arr.slice();

arr2[0].one = 'two';
arr[1][0] = [4,5,6];
console.log(arr);
//[ { one: 'two' }, [ [ 4, 5, 6 ], 2, 3 ] ]
console.log(arr2);
//[ { one: 'two' }, [ [ 4, 5, 6 ], 2, 3 ] ]

可以发现arr和arr1都发生了变化,克隆的并不彻底。如果数组元素是基本类型,就会拷贝一份,互不影响,而如果是对象或者数组,就会只拷贝对象和数组的引用,这样我们无论在新旧数组进行了修改,两者都会发生变化。

深拷贝:

如何实现深拷贝呢?

1.此方法只适用于 Number, String, Boolean, Array 的扁平对象

用 JSON.stringify 把对象转成字符串,再用 JSON.parse 把字符串转成新的对象

var arr = ['abc',[1,2,3],true,{one:1}]

var arr2 = JSON.parse(JSON.stringify(arr));

arr[3].one = 2;
arr2[1][0] = 0;
console.log(arr);
//[ 'abc', [ 1, 2, 3 ], true, { one: 2 } ]
console.log(arr2);
//[ 'abc', [ 0, 2, 3 ], true, { one: 1 } ]

2.深拷贝实现(递归实现)

var deepCopy = function(obj){
	if (typeof obj != 'object') return;
	var new_obj = obj instanceof Array ? [] : {};
	for (var key in obj) {
		if (obj.hasOwnProperty(key)) {
			new_obj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];		
		}
	}
	return new_obj;
}

var obj = {
	str: 'abc',
	num: 123,
	a: {
		n: 10
		//flag: true
	}
}

var obj2 = deepCopy(obj);
obj.str = 'cde';
obj2.a.n = 9;
console.log(obj);
//{ str: 'cde', num: 123, a: { n: 10 } }
console.log(obj2);
//{ str: 'abc', num: 123, a: { n: 9 } }

最后总结赋值、浅拷贝、深拷贝

 

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

参考文章https://mp.weixin.qq.com/s?src=11×tamp=1590028308&ver=2351&signature=HV0OEzUBVR9VT-K*OazkdG9hpUnKC1qHs4H1VdjIlWtsDuiLZkGe5oNbW79FdJi-ufb95Byver4If0k9313thFd6E3aXSYvysr3W2SzcR0o*Oljo7ShCmojAhL1pPPuu&new=1

https://mp.weixin.qq.com/s?src=11×tamp=1590028389&ver=2351&signature=aIT29L2e4*UKkoYukg3rGyD10AH4*zm95mg3V4FbLHh6r4F4iXk0vgpW*kDR3Lt09P7ZKr8SAcSnwEFI9uNSO8yqxXz0OT7TYRdKtOMboFIQQ8YS8czgWSPehBzSqmn7&new=1

https://mp.weixin.qq.com/s?src=11×tamp=1590035045&ver=2351&signature=WDC4lZlQdgOW9OBSE-rU-D73PQiJq1I2Lh8JijhIpBECAiSQBdPB*Xniu-ccbhjsm4pNJHf-widapHhieBatYVtGhtJEde1IiD5CR7d0J2FpCnTTW2P12WjAq-5XyTLC&new=1

https://www.cnblogs.com/echolun/p/7889848.html

 

你可能感兴趣的:(前端)