1. 程式人生 > >JS JavaScript深拷貝、淺拷貝

JS JavaScript深拷貝、淺拷貝

ice 三種方式 bsp clone == ava 目標 .... yar

淺拷貝:淺拷貝只是復制了內存地址,如果原地址中的對象改變了,淺復制出來的對象也會相應改變。

深拷貝:開辟了一塊新的內存存放地址和地址指向的對象。

深拷貝數組(只拷貝第一級數組):

1.直接遍歷

var arr = [1,2,3,4];


function copy(arg){
  
  var newArr = [];
  
  for(var i = 0; i < arr.length; i++) {
    newArr.push(arr[i]);
  }
  
  return newArr;
}

var newArry = copy(arr);
console.log(newArry);
newArry[
0] = 10; console.log(newArry); // [10,2,3,4] console.log(arr) // [1,2,3,4]

2.slice

var arr = [1,2,3,4]
var copyArr = arr.slice();
copyArr[0] = 10;
console.log(copyArr); // [10,2,3,4]
console.log(arr); // [1,2,3,4]

slice(start,end),slice()方法返回一個數組中復制出來的元素組成新數組,start指起始元素下標,end指終止元素下標

當slice()不帶任何參數時,默認返回一個和原數組一樣的新數組

3.concat()

var arr = [1,2,3,4]
var copyArr = arr.concat();
copyArr[0] = 10;
console.log(copyArr); // [10,2,3,4]
console.log(arr); // [1,2,3,4]

array.concat(array1,array2,.......,arrayN),concat()方法用於連接兩個或多個數組(不會改變原數組,返回被連接數組的副本)

然而如果第一級數組元素是對象或數組,上面三種方式都失效:

var arr = [
  {number:1},
  {number:2},
  {number:
3} ] var copyArr = arr.slice(); copyArr[0].number = 10; console.log(copyArr); // [{number: 100}, { number: 2 },{ number: 3 }] console.log(arr); // [{number: 100}, { number: 2 }, { number: 3 }]

深拷貝對象(如果對象中的值不為數組或對象)

1.直接遍歷

  var obj = {
    name: "張三",
    job: "學生"
  }
  
  function copy (arg) {
    let newobj = {}
    for(let item in obj) {
      newobj[item] = obj;
    }
    return newobj;
  }
  
  var copyobj = copy(obj)
  copyobj.name = "李四"
  console.log(copyobj) // {name: ‘李四‘, job:: ‘學生‘}
  console.log(obj) // {name: ‘張三‘, job:: ‘學生‘}

2.ES6的Object.assign

var obj = {
  name: ‘張三‘,
  job: ‘學生‘
}

var copyobj = Object.assign({},obj)
copyobj.name = ‘李四‘
console.log(copyobj) // {name: ‘李四‘, job:: ‘學生‘}
console.log(obj)    // {name: ‘張三‘, job:: ‘學生‘}

Object.assign:用於對象的合並,將源對象(source)的所有可枚舉屬性,復制到目標對象(target),並返回合並後的target

用法: Object.assign(target, source1, source2); 所以 copyObj = Object.assign({}, obj); 這段代碼將會把obj中的一級屬性都拷貝到 {}中,然後將其返回賦給copyObj

3.ES6擴展運算符
var obj = {
  name: ‘張三‘,
  job: ‘學生‘
}

var copyobj = {...obj}
copyobj.name = ‘李四‘
console.log(copyobj)
console.log(obj)

擴展運算符(...)用於取出參數對象的所有可遍歷屬性,拷貝到當前對象之中

JSON.stringfy()和JSON.parse

用JSON.stringify把對象轉成字符串,再用JSON.parse把字符串轉成新的對象。

但是這種方法也有不少壞處,譬如它會拋棄對象的constructor。也就是深拷貝之後,不管這個對象原來的構造函數是什麽,在深拷貝之後都會變成Object。

這種方法能正確處理的對象只有 Number, String, Boolean, Array, 扁平對象,即那些能夠被 json 直接表示的數據結構。RegExp對象是無法通過這種方式深拷貝。

也就是說,只有可以轉成JSON格式的對象才可以這樣用,像function沒辦法轉成JSON。

var obj1 = { fun: function(){ console.log(123) } };
var obj2 = JSON.parse(JSON.stringify(obj1));
console.log(typeof obj1.fun);
// ‘function‘
console.log(typeof obj2.fun);
// ‘undefined‘ <-- 沒復制

使用遞歸函數實現一個深拷貝的方法

function deepClone(obj) {
    let objClone = Array.isArray(obj) ? [] : {};
    if(obj && typeof obj === "object") {
        for(key in obj) {
            if(obj.hasOwnProperty(key)) {
                if(obj[key] && typeof obj[key] === "object") {
                    objClone[key] = deepClone(obj[key]);
                } else {
                    objClone[key] = obj[key];    
                }
             }
         } 
    }
    return objClone
}            

JS JavaScript深拷貝、淺拷貝