前端JS:什麼是深拷貝?什麼是淺拷貝?

GeekQiaQia發表於2019-04-24

#追根溯源

javascript 資料型別:

  • 值型別(基本資料型別):String,Number,Boolean,Null,Undefined,Symbol

  • 引用資料型別資料

  • Object,Array,Function

    重點宣告:Undefined 和 Null的區別;

  • Undefined 表示變數不含有值;

  • null:可以通過將變數的值設定為null來清空變數;

      {
      	var person,
      		car="moto";
      	 console.log(person);//undefined;
      	 console.log(car); // moto;
      	   car=null;
      	 console.log(car); // null		
      }
    複製程式碼

堆stack 和 棧heap

什麼是堆記憶體&&什麼是棧記憶體?

  • stack:為自動分配的記憶體空間,它由系統自動釋放;
  • heap:為動態分配的記憶體空間,它大小不一定,也不會自動釋放;

值 && 引用

  • 值資料型別的變數和值都存放在棧記憶體中,在變數申明之後,會動態分配一塊記憶體區域,基本資料型別之間的賦值:是直接把棧記憶體中存的值,傳值給變數;(傳值)
  • 引用型別的變數存在棧記憶體中,但是值存在堆記憶體中;實際上棧存放的是,指向堆中的地址,即“引用”。引用型別直接的賦值,實質上是把“引用”賦值給一個變數(傳址),所以其指向的堆記憶體中的值是一樣的;

深拷貝和淺拷貝

  • 使用場景:
    • 深拷貝:在複雜物件裡,物件的屬性也是物件的時候;
    • 淺拷貝:只複製一層物件,當物件的屬性是引用型別時,實質上覆制的是其引用,當引用指向的值發生變化的時候,原物件屬性值也跟著變化;

淺拷貝

將原物件/原陣列的引用,直接賦給新物件/新陣列,新物件/陣列只是原物件的一個引用, Just show the code :

	舉例1:
		let obj={a:1,arr:[2,3]};	

		let shallowObj=shallowCopy(obj);
		
		function shallowCopy(srcObj){
			var dest={};
			for(let prop in srcObj){
					console.log(prop);
				if(srcObj.hasOwnProperty(prop)){
					dest[prop]=srcObj[prop]
					

					}

				}// end of loop
				
				return dest;
			} 
		
// 1.舉例: 當一個物件屬性的引用值改變時,會導致另一個也改變;
	
	shallowObj.arr[1]=5;
	console.log(obj.arr[1]); // 5
	
// 2.舉例:console:

	let obj2=obj;
		
		obj2
		{a: 1, arr: Array(2)}
		obj2.arr
		(2) [2, 3]
		obj2.arr[1]=4
		4
		obj2.arr
		(2) [2, 4]
		obj.arr
		(2) [2, 4]
複製程式碼

深拷貝:

是指,建一個新的物件和陣列,將原物件的各項屬性的“值”(陣列的所有元素)拷貝過來,是“值”而不是“引用” 我們希望在改變新的陣列(物件)的時候,不改變原陣列(物件)

1.只對第一層級深拷貝

1.直接遍歷:

var array = [1, 2, 3, 4];
function copy (array) {
   let newArray = []
   for(let item of array) {
      newArray.push(item);
   }
   return  newArray;
}
var copyArray = copy(array);
copyArray[0] = 100;
console.log(array); // [1, 2, 3, 4]
console.log(copyArray); // [100, 2, 3, 4]
複製程式碼

2.slice(); arrObj.slice(start,end);

slice() 方法返回一個從已有的陣列中擷取一部分元素片段組成的新陣列

var array = [1, 2, 3, 4];
var copyArray = array.slice();
copyArray[0] = 100;
console.log(array); // [1, 2, 3, 4]
console.log(copyArray); // [100, 2, 3, 4]
複製程式碼

3.concat();arrObj.concat(arr1,arr2...);

var array = [1, 2, 3, 4];
var copyArray = array.concat();
copyArray[0] = 100;
console.log(array); // [1, 2, 3, 4]
複製程式碼

因為我們上面呼叫concat的時候沒有帶上引數,所以var copyArray = array.concat();實際上相當於var copyArray = array.concat([]);

也即把返回陣列和一個空陣列合並後返回

4.ES6的Object.assign();

Object.assign:用於物件的合併,將源物件(source)的所有可列舉屬性,複製到目標物件(target),並返回合併後的target Object.assign(target, source1, source2);

	var obj = {
	  name: '彭湖灣',
	  job: '學生'
	}
	var copyObj = Object.assign({}, obj);
	copyObj.name = '我才不叫彭湖灣呢! 哼  (。・`ω´・)';
	console.log(obj);   // {name: "彭湖灣", job: "學生"}
	console.log(copyObj);  // {name: "我才不叫彭湖灣呢! 哼  (。・`ω´・)", job: "學生"}
複製程式碼

所以copyObj=Object.asssign({},obj);是將程式碼中obj的一級屬性,拷貝到{}中,然後將其返回給copyObj;

5 ES6擴充套件運算子:

擴充套件運算子(...)用於取出引數物件的所有可遍歷屬性,拷貝到當前物件之中 var copyObj=[...arr] function copy(obj){ if(typeof obj !==="object"){ return ; }

		let newObj= obj.constructor===Array?[]:{};

		if(newObj instanceof Array){
			 newObj=[...obj];
			return	newObj;
		}else if(newObj instanceof Object){
			newObj={...obj};	
			return newObj;
		} 

		}
複製程式碼

多次級深拷貝;

1.遞迴方式實現深拷貝

	function deepCopy(obj){

		if(obj instanceof Array){
		let n=[];
		for(let i=0;i<obj.length;i++){
		
			n[i]=deepCopy(obj[i]);
			
			}// end of for
			return n;
		}// end of if ;
		if(obj instanceof Object){
		let n={};
			for(let i in obj){
		      n[i]=deepCopy(obj[i]);
			
			}// end of for
		 return n;	
		} else { //// end of if 
		
		 return obj;
	
		}
	}
複製程式碼

2.JSON.parse(JSON.stringify(strObj));

	var arrObj=[
		{num:1},
		{num:2},
		{num:3}
	];
	var copyArray=JSON.parse(JSON.stringify(arrObj));
	
	copyArray[2].num=4;

    console.log(arrObj); // [{num:1},{num:2},{num:3}];
	console.log(copyArray); // [{num:1},{num:2{num:4}];
複製程式碼

3.遞迴2:

	function copy(obj){
		let newObj=obj.constructor===Array?[]:{};
		if(type of obj !="object"){
			return;
		}
        for(let i in obj){
		newObj[i]= typeof obj[i]==="object"?copy(obj[i]):obj[i]
		
		}
		return newObj;
	}
複製程式碼

相關文章