工作日常--js引用型別資料深拷貝與淺拷貝
阿新 • • 發佈:2018-12-30
js資料型別
簡單資料型別
簡單的資料型別包括
Undifine,NULL,Bolean,String,Number
。這些資料型別的資料的儲存是在堆中儲存的。堆中存放的資料是先進先出。FIFO(first in first out)引用型別
引用型別包括Object和Array,引用資料型別是存放在棧中的。棧中存放的資料是先進後出的。FILO(frist in last out)
關於js的淺拷貝和深拷貝
++只有引用資料型別才會有深拷貝和淺拷貝這麼一說。由於js的儲存都是存地址的,淺拷貝會導致obj1和obj2指向同一個記憶體地址。這麼一來,如果操作其中的任意一個obj那麼就會導致元記憶體地址的資料更改。所以需要使用到深拷貝,為拷貝出的物件開闢一塊新的記憶體地址。這樣一來,就會出現原物件與新拷貝的物件在不同的記憶體地址。從而達到前後物件相互不影響。++
淺拷貝
陣列的淺拷貝
var oldArray = [1,2,3,4,5,6];
var newArray = [];
newArray = oldArray;
newArray[0] = '改變的元素';
console.log(oldArray); // '改變的元素',2,3,4,5,6
console.log(newArray); // '改變的元素',2,3,4,5,6
物件的淺拷貝
function copyObject(obj){
var outObj = {};
for(var item in obj){
outObj.item = obj[item];
}
return outObj;
}
// Object.assign() 將元物件的屬性列舉到新的物件,然後返回新的物件
var obj = {
name:'二貨',
sex:'male',
age:23
}
var b = {};
Object.assign(b,obj);
if(b === obj) // true
深拷貝
陣列的concat與slice方法(假裝深拷貝)
++concat與slice方法都是淺拷貝一個數組的元素然後拷貝給一個新的陣列。只是如果陣列的單個元素是數字,字串等簡單資料型別的時候,原陣列的物件不會受新陣列的影響。如果陣列的項是引用型別陣列或物件,則就是淺拷貝。++
var origin = [1,2,3,4,5];
var copySlice = origin.slice(0);
var copyConcat = origin.concat();
copySlice[0] = 'one';
copyConcat[0] = 'concat';
console.log(origin); // [1,2,3,4,5]
var origin = [[1,2,3],{name:'lol'}];
var copySlice = origin.slice(0);
var copyConcat = origin.concat();
copySlice[0][0] = 'slice';
copyConcat[1].name = 'concat';
console.log(origin) // [['slice',2,3],{name:'concat'}]
深拷貝實現方法JSON.parse和JSON.stringify();
這種方法使用較為簡單,可以滿足基本的深拷貝需求,而且能夠處理JSON格式能表示的所有資料型別,但是對於正則表示式型別、函式型別等無法進行深拷貝(而且會直接丟失相應的值)。還有一點不好的地方是它會拋棄物件的constructor。也就是深拷貝之後,不管這個物件原來的建構函式是什麼,在深拷貝之後都會變成Object。同時如果物件中存在迴圈引用的情況也無法正確處理。
//例1
var source = { name:"source", child:{ name:"child" } }
var target = JSON.parse(JSON.stringify(source));
target.name = "target"; //改變target的name屬性
console.log(source.name); //source
console.log(target.name); //target
target.child.name = "target child"; //改變target的child
console.log(source.child.name); //child
console.log(target.child.name); //target child
//例2
var source = { name:function(){console.log(1);}, child:{ name:"child" } }
var target = JSON.parse(JSON.stringify(source));
console.log(target.name); //undefined
//例3
var source = { name:function(){console.log(1);}, child:new RegExp("e") }
var target = JSON.parse(JSON.stringify(source));
console.log(target.name); //undefined
console.log(target.child); //Object {}