1. 程式人生 > >工作日常--js引用型別資料深拷貝與淺拷貝

工作日常--js引用型別資料深拷貝與淺拷貝

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 {}