現在的位置: 首頁 > web前端 > 正文

什麼是對象的拷貝?JavaScript對象的深淺拷貝總結

2020年02月21日 web前端 ⁄ 共 3257字 ⁄ 字型大小 評論關閉

  什麼是對象的拷貝?

  將一個對象賦值給另外一個對象, 我們稱之為對象的拷貝。

  什麼是深拷貝, 什麼是淺拷貝?

  我們假設將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.

  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對象也收到影響,屬於淺拷貝。

  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對象的屬性和方法, 我們稱之為深拷貝。

  以下兩種情況都屬於深拷貝:

  5.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}

  這樣就實現了深拷貝。

  5.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對象,完成深拷貝。

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

  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

  }

  5.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=2

  obj1.b.push(4);

  console.log(obj1); //{a:2,b:[1,2,3,4]}

  console.log(obj2); //{a:1,b:[1,2,3]}

  以上就是有關JavaScript對象的淺拷貝與深拷貝的相關介紹,如要了解更多前端以及JavaScript的知識,請持續關注學步園。

抱歉!評論已關閉.