前端JS:什麼是深拷貝?什麼是淺拷貝?
-
值型別(基本資料型別):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); } returnnewArray; } 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]; returnnewObj; }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; } 複製程式碼