Object.assign () 和深拷貝


先看看啥叫深拷貝?啥叫淺拷貝?

假設B復制了A,修改A的時候,看B是否發生變化:

如果B跟着也變了,說明是淺拷貝,拿人手短!(修改堆內存中的同一個值)
如果B沒有改變,說明是深拷貝,自食其力!(修改堆內存中的不同的值)

深拷貝(deepCopy)是增加了一個指針並且申請了一個新的內存,使這個增加的指針指向這個新的內存,使用深拷貝的情況下,釋放內存的時候不會因為出現淺拷貝時釋放同一個內存的錯誤。

淺拷貝(shallowCopy)只是增加了一個指針指向已存在的內存地址

簡單理解:

深拷貝(深復制):在計算機中開辟一塊新的內存地址用於存放復制的對象。

淺拷貝(淺復制):僅僅是指向被復制的內存地址,如果原地址發生改變,那么淺復制出來的對象也會相應的改變。

MDN Web開發文檔上對Object.assign()得解釋:

Object.assign() 方法用於將所有可枚舉屬性的值從一個或多個源對象復制到目標對象。它將返回目標對象。

官網示例:

const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };

const returnedTarget = Object.assign(target, source);

console.log(target);
// expected output: Object { a: 1, b: 4, c: 5 }

console.log(returnedTarget);
// expected output: Object { a: 1, b: 4, c: 5 }

語法:   Object.assign(target, ...sources)

參數:target目標對象、sources源對象。

返回值:目標對象。

作用話根據官網來看:復制一個對象、拷貝對象(當對象中只有一級屬性,沒有二級屬性的時候,此方法為深拷貝,但是對象中有對象的時候,此方法,在二級屬性以后就是淺拷貝。)、合並對象。

描述:

如果目標對象中的屬性具有相同的鍵,則屬性將被源對象中的屬性覆蓋。后面的源對象的屬性將類似地覆蓋前面的源對象的屬性。

Object.assign 方法只會拷貝源對象自身的並且可枚舉的屬性到目標對象。該方法使用源對象的[[Get]]和目標對象的[[Set]],所以它會調用相關 getter 和 setter。因此,它分配屬性,而不僅僅是復制或定義新的屬性。如果合並源包含getter,這可能使其不適合將新屬性合並到原型中。為了將屬性定義(包括其可枚舉性)復制到原型,應使用Object.getOwnPropertyDescriptor()Object.defineProperty() 。

String類型和 Symbol 類型的屬性都會被拷貝。

在出現錯誤的情況下,例如,如果屬性不可寫,會引發TypeError,如果在引發錯誤之前添加了任何屬性,則可以更改target對象。

注意:Object.assign 不會在那些source對象值為 null 或 undefined 的時候拋出錯誤。

Object.assign()對象的深拷貝

針對深拷貝,需要使用其他辦法,因為 Object.assign()拷貝的是屬性值。假如源對象的屬性值是一個對象的引用,那么它也只指向那個引用。
let obj1 = { a: 0 , b: { c: 0}}; 
let obj2 = Object.assign({}, obj1); 
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}} 

obj1.a = 1; 
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}} 
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}} 

obj2.a = 2; 
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}} 
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 0}}
 
obj2.b.c = 3; 
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 3}} 
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 3}} 
最后一次賦值的時候,b是值是對象的引用,只要修改任意一個,其他的也會受影響

// Deep Clone (深拷貝)
obj1 = { a: 0 , b: { c: 0}}; 
let obj3 = JSON.parse(JSON.stringify(obj1)); 
obj1.a = 4; 
obj1.b.c = 4; 
console.log(obj3); // { a: 0, b: { c: 0}}

遞歸的方式實現深拷貝

  function _deepClone(source) {
    let target;
    if (typeof source === 'object') {
      target = Array.isArray(source) ? [] : {}
      for (let key in source) {
        if (source.hasOwnProperty(key)) {
          if (typeof source[key] !== 'object') {
            target[key] = source[key]
          } else {
            target[key] = _deepClone(source[key])
          }
        }
      }
    } else {
      target = source
    }
    return target
  }

  const obj = {
    a: {
      aa: 1,
      aaa: 2
    },
    b: 2,
    c: 3
  }
  var obj2 = _deepClone(obj)
  obj.b = 9
  console.log(obj2) //{a: {aa: 1,aaa: 2}, b: 2, c: 3}
  console.log(obj) //{a: {aa: 1,aaa: 2}, b: 9, c: 3}

js實現深拷貝

  const obj = {
    a: {
      aa: 1,
      aaa: 2
    },
    b: 2,
    c: 3
  }
  let obj3 = JSON.parse(JSON.stringify(obj));
  obj.a.aa = 4;
  obj.b = 9;
  console.log(obj3); // {a: {aa: 1,aaa: 2}, b: 2, c: 3}
  console.log(obj) // {a: {aa: 4,aaa: 2}, b: 9, c: 3}

本文參考:

MDN Web文檔

Object.assign () 和深拷貝


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM