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帶來的困擾,也避免了在遍歷的時候因相互調用對象導致的情況。
用一張話來結束深拷貝和淺拷貝的區別
淺拷貝就是新舊對象引用同一個內存空間,一個改變則全部改變,即:一變全變;深拷貝就是舊對象引用原來的空間,新對象則新建空間,自己控制自己的大小。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章