天天看點

ES6 深拷貝_總結JavaScript對象的深淺拷貝

什麼是對象的拷貝?将一個對象指派給另外一個對象, 我們稱之為對象的拷貝什麼是深拷貝, 什麼是淺拷貝?我們假設将A對象指派給B對象淺拷貝是指, 修改B對象的屬性和方法會影響到A對象的屬性和方法, 我們稱之為淺拷貝以下兩種情況都屬于淺拷貝:1、預設情況下對象之間的 直接指派 都是淺拷貝let A = { name: 'zyx', age: 20 } let B = A console.log(B) // {name: "zyx", age: 20} //修改B的 name 屬性 B.name = 'ls' //A 也收到影響 console.log(A) // {name: "ls", age: 20} console.log(B) // {name: "ls", age: 20}​ 指派操作(包括對象作為參數、傳回值),不會開辟新的記憶體空間,他隻是指派了對象的引用.也就是除了B這個名字之外,沒有其他的記憶體開銷,修改了A也就影響了B,修改了B,也就影響了A.如圖所示:

ES6 深拷貝_總結JavaScript對象的深淺拷貝

2、如果 對象的屬性包含了引用資料類型(數組、對象) ,那麼哪怕不是直接指派操作,而是開辟了一層新的記憶體空間,也就是說隻拷貝了A對象的一層,這仍然屬于淺拷貝。

let A = {      name: 'ls',      age: 20,      hobbies: ['dance','basketball','read'],      dogs:{       name: '大黃',       color: 'yellow'      }    } let B = {} //定義一個函數,把A對象的屬性複制一份給B function extend(obj1,obj2){     for(var key in obj1){         obj2[key] = obj1[key]     } } extend(A,B)//修改B對象中的引用類型資料 ,A對象也收到影響B.dogs.color = 'red'B.hobbies[0] = 'sing'console.log(B) console.log(A)           

運作截圖如下:修改B對象中的引用類型資料 ,A對象也收到影響,屬于淺拷貝

ES6 深拷貝_總結JavaScript對象的深淺拷貝

3、ES6中新增的 Object.assign() 也是對象的淺拷貝

Object.assign 方法用于對象的合并,将源對象(source)的所有可枚舉屬性,複制到目标對象(target)。 Object.assign 方法的第一個參數是目标對象,後面的參數都是源對象。 注意,如果目标對象與源對象有同名屬性,或多個源對象有同名屬性,則後面的屬性會覆寫前面的屬性。

const obj1 = {a: {b: 1}};const obj2 = Object.assign({}, obj1);obj1.a.b = 2;obj2.a.b // 2           

上面代碼中,源對象 obj1 的 a 屬性的值是一個對象, Object.assign 拷貝得到的是這個對象的引用。這個對象的任何變化,都會反映到目标對象上面。

4、擴充運算符(...)

利用擴充運算符可以在構造字面量對象時,進行克隆或者屬性拷貝 ,屬于淺拷貝

var obj = {a:1,b:{c:1}}var obj2 = {...obj};obj.a=2;console.log(obj); //{a:2,b:{c:1}}console.log(obj2); //{a:1,b:{c:1}}obj.b.c = 2;console.log(obj); //{a:2,b:{c:2}}console.log(obj2); //{a:1,b:{c:2}}           

5、Array.prototype.slice()

slice() 方法傳回一個新的數組對象,這一對象是一個由 begin和 end(不包括end)決定的原數組的淺拷貝。原始數組不會被改變。

  • 深拷貝是指, 修改B對象的屬性和方法不會影響到A對象的屬性和方法, 我們稱之為深拷貝以下兩種情況都屬于深拷貝:1、預設情況下一個 對象的屬性如果是基本資料類型 , 那麼進行複制(拷貝),都是深拷貝如果A對象的屬性都是基本資料類型(Number、String等),此時要想深拷貝一份A給B,該怎麼做呢,在這種 要拷貝的對象A隻有基本類型的資料時 ,隻需要在記憶體中開辟一塊空間存儲B就行了。let A = { name: 'zyx', age: 20 } let B = {} //定義一個函數,把A對象的屬性複制一份給B function extend(obj1,obj2){ for(var key in obj1){ obj2[key] = obj1[key] } } extend(A,B) console.log(B) // {name: "zyx", age: 20} B.name = 'ls' console.log(B) // {name: "ls", age: 20} console.log(A) // {name: "zyx", age: 20}這樣就實作了深拷貝,如下圖所示:
ES6 深拷貝_總結JavaScript對象的深淺拷貝

2、如果 要拷貝的對象本身又包含了引用資料類型 ,即對象又包含數組或者對象,層層嵌套的情況下,想要實作對象的深拷貝,可以采用 遞歸 的方式進行深拷貝。

let A = {    name: 'ls',    age: 20,    hobbies: ['dance','basketball','read'],    dogs:{      name: '大黃',      color: 'yellow'    }  }  let B = {}  //定義一個函數,把A對象的屬性複制一份給B  function extend(obj1,obj2){    for(var key in obj1){      var item = obj1[key]      if(item instanceof Array){        obj2[key] = []        extend(item,obj2[key])      }else if(item instanceof Object){        obj2[key] = {}        extend(item,obj2[key])      }else{        obj2[key] = item      }    }  }  extend(A,B)  B.dogs.color = 'red'  B.hobbies[0] = 'sing'  console.log(B)  console.log(A)           

運作發現,修改B對象的引用資料類型,不會影響到A對象,完成深拷貝

ES6 深拷貝_總結JavaScript對象的深淺拷貝

我們可以對深拷貝的代碼進行封裝優化

function deepClone(obj){    let cloneObj = {}    for(let key in obj){        if(typeof obj[key] === 'object'){            cloneObj[key] = deepClone(obj[key])        }else{            cloneObj[key] = obj[key]        }     }    return cloneObj}           

3、通過JSON.stringify實作深拷貝

JSON.stringify()是目前前端開發過程中最常用的深拷貝方式,原理是把一個對象序列化成為一個JSON字元串,将對象的内容轉換成字元串的形式再儲存在磁盤上,再用JSON.parse()反序列化将JSON字元串變成一個新的對象。

var obj1 = {    a:1,    b:[1,2,3]}var str = JSON.stringify(obj1)var obj2 = JSON.parse(str)console.log(obj2); //{a:1,b:[1,2,3]}obj1.a=2obj1.b.push(4);console.log(obj1); //{a:2,b:[1,2,3,4]}console.log(obj2); //{a:1,b:[1,2,3]}           

繼續閱讀