js深拷贝与浅拷贝解析与实现

在js的语法中,像Number,String,Boolean这样的基本类型,它们的传值方式是按值传递的,而想对象{a: 10, b: 20},它们的传值是引用传值的
对于对象来说,在这里就总结一下深拷贝和浅拷贝时遇到的问题。
基本类型的按值传递,比如:a = 10, b = a,系统会为a和b 分配不同的内存空间,彼此之间相互不影响。
 

		var a = 10;
		var b = a;
		b = 20;
		console.log(a);   //输出结果为10
		console.log(b);   //输出结果为20

但是对于对象来说,结果就截然相反。
浅拷贝

	   var obj1 = {
			a: 10,
			b: {
				a: 'yf',
				b: 'bl'
			},
			c: ['Bob','Tom','nick'],
			d: function(){
				console.log('Hello World');
			}
		};
		var obj2 = obj1;
		obj2.a = 30;
		console.log(obj1);
		console.log(obj2);
		console.log(obj1 === obj2);

输出结果如下:

由上面的代码块我可以很清楚的看到,obj1、obj2引用了同一块内存空间,虽然我们对我obj2 进行了赋值操作,相当于给整个内存空间进行了赋值,所以obj1、obj2都进行了修改,这个就是所谓的浅拷贝。
深拷贝
1、使用JSON数据解析实现深拷贝。

// 使用JSON数据解析来实现深度拷贝(JSON不能够识别Function类型)
			var obj1 = {
				a: 10,
				b: {
					a: 'yf',
					b: 'bl'
				},
				c: ['Bob','Tom','nick'],
				d: function(){
					console.log('Hello World');
				}
			};
		function deepClone(obj){
			return JSON.parse(JSON.stringify(obj));
		}
		var e = deepClone(obj1);
		e.a = 20;
		console.log(e);
		console.log(obj1);
		// 通过类型检测判断JSON是不识别Function类型的
		console.log(typeof e.d);
		console.log(typeof obj1.d);

输出的结果如下所示:

使用JSON数据解析的这种方式是比较容易理解的,我们使用JSON.stringify将其转化为JSON字符串,这个时候重新生成的字符串和原来的对象是没有什么关系的,也就是说为字符串重新开辟了一个内存空间,然后我们使用JSON.parse将其转化为对象,此时在新旧对象上的操作是彼此独立的,所以我们输出的结果中a的值是不同的。
**缺点:**这种方法存在一个致命性的错误,不能够识别对象中的Function类型,JSON.stringify()不能够识别Function,会返回undefined,所以这个方法只能用于只有数据的对象中。这个方法会抛弃对象的constructor,深拷贝之后,不管对象的构造函数是什么,都会将其变成Object。
为了解决这个问题,我们采用递归的方法来对 对象中的属性进行遍历输出。
2、递归拷贝
 

	function deepClone(Obj1, Obj2) {    
  			var obj = Obj2 || {};    
  			for (var i in Obj1) {        
    			var prop = Obj1[i]; 
    			// 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
    			if(prop === obj) {            
      			continue;
    		}        
   			if (typeof prop === 'object') {
    			obj[i] = (prop.constructor === Array) ? [] : {};            
      			arguments.callee(prop, obj[i]);
    		} else {
      			obj[i] = prop;
    		}
  		}    
  		return obj;
	}
	var str = {};
	var obj = { a: {a: "hello", b: 21, c: function(){alert('hello world');}}};
	deepClone(obj, str);
	console.log(str.a);

采用递归的方法,我们成功的解决了Function带来的困扰,也避免了在遍历的时候因相互调用对象导致的情况。
用一张话来结束深拷贝和浅拷贝的区别:
浅拷贝就是新旧对象引用同一个内存空间,一个改变则全部改变,即:一变全变;深拷贝就是旧对象引用原来的空间,新对象则新建空间,自己控制自己的大小。
 

猜你喜欢

转载自blog.csdn.net/qq_36742720/article/details/90449213