經典前端面試題: Object.assign 是淺拷貝仍是深拷貝?實現深拷貝的方法有哪些?

Object.assign() 方法用於將全部可枚舉屬性的值從一個或多個源對象複製到目標對象。它將返回目標對象。前端

  • 若是目標對象中的屬性具備相同的鍵,則屬性將被源對象中的屬性覆蓋。後面的源對象的屬性將相似地覆蓋前面的源對象的屬性。jquery

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

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

  • 在出現錯誤的狀況下,例如,若是屬性不可寫,會引起TypeError,若是在引起錯誤以前添加了任何屬性,則能夠更改target對象。面試

  • Object.assign 不會在那些source對象值爲 nullundefined 的時候拋出錯誤。數組

  • 針對深拷貝,須要使用其餘辦法,由於 Object.assign()拷貝的是屬性值。假如源對象的屬性值是一個對象的引用,那麼它也只指向那個引用。也就是說,若是對象的屬性值爲簡單類型(如string, number),經過Object.assign({},srcObj);獲得的新對象爲深拷貝;若是屬性值爲對象或其它引用類型,那對於這個對象而言實際上是淺拷貝的。bash

深拷貝的幾種實現方法

JSON.stringify 和 JSON.parse

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

能夠轉成 JSON 格式的對象才能使用這種方法,若是對象中包含 function 或 RegExp 這些就不能用這種方法了。spa

//經過js的內置對象JSON來進行數組對象的深拷貝
function deepClone(obj) {
  let _obj = JSON.stringify(obj);
  let objClone = JSON.parse(_obj);
  return objClone;
}
複製代碼

Object.assign()拷貝

當對象中只有一級屬性,沒有二級屬性的時候,此方法爲深拷貝,可是對象中有對象的時候,此方法,在二級屬性之後就是淺拷貝。code

經過jQuery的extend方法實現深拷貝

let $ = require('jquery');
let obj1 = {
   a: 1,
   b: {
     f: {
       g: 1
     }
   },
   c: [1, 2, 3]
};
let obj2 = $.extend(true, {}, obj1);
複製代碼

lodash.cloneDeep()實現深拷貝

let _ = require('lodash');
let obj1 = {
    a: 1,
    b: { f: { g: 1 } },
    c: [1, 2, 3]
};
let obj2 = _.cloneDeep(obj1);
複製代碼

使用遞歸的方式實現深拷貝

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
}
複製代碼

更多經典前端面試題,請到github查看或參與討論github.com/daily-inter…

相關文章
相關標籤/搜索