js對象淺拷貝與深拷貝

js對象淺拷貝與深拷貝

  • javascript中Object、Array是引用類型,棧內存中存儲內存地址,堆內存存儲值,所以在引用類型的拷貝中,存在淺拷貝、深拷貝。下文將經過示例加以說明。
  • 由於基本類型和引用類型的區別,注意函數值傳遞的區別,這裏不加以詳細說明。

淺拷貝

  • 若是對象裏只用值類型的屬性,能夠使用擴展符(...)或 Object.assign(...)拷貝
<!--擴展符-->
var obj = { foo: "foo", bar: "bar" };
var copy = { ...obj }; // Object { foo: "foo", bar: "bar" }

<!--assign-->
var obj = { foo: "foo", bar: "bar" };
var copy = Object.assign({}, obj); // Object { foo: "foo", bar: "bar" }
複製代碼
  • 注意,上述兩種方法均可用於將屬性值從多個源對象複製到目標對象,示例
var obj1 = { foo: "foo" };
var obj2 = { bar: "bar" };

var copySpread = { ...obj1, ...obj2 }; // Object { foo: "foo", bar: "bar" }
var copyAssign = Object.assign({}, obj1, obj2); // Object { foo: "foo", bar: "bar" }
複製代碼
  • 上述方法的問題在於,對於具備屬性自己對象的對象,只複製引用,示例
var foo = { a: 0 , b: { c: 0 } };
var copy = { ...foo };

copy.a = 1;
copy.b.c = 2;

console.dir(foo); // { a: 0, b: { c: 2 } }
console.dir(copy); // { a: 1, b: { c: 2 } }
console.log(copy.b === foo.b) // true
複製代碼

深拷貝

  • 利用JSON將對象序列化爲字符串,而後將其反序列化。
var obj = { a: 0, b: { c: 0 } };
var copy = JSON.parse(JSON.stringify(obj));
console.log(copy.a === obj.b) // false
複製代碼
  • 遺憾的是,此方法僅在源對象包含可序列化值類型且沒有任何循環引用時纔有效。
<!--函數丟失-->
var obj = { a: 0, b: { c: 0 }, d: function() {console.log('------>')} };
var copy = JSON.parse(JSON.stringify(obj));

console.log(copy) // {a: 0, b: {…}}

<!--日期對象將被轉換爲字符串化上以ISO格式打印-->
var obj = { a: 0, b: { c: 0 }, f: new Date() };
var copy = JSON.parse(JSON.stringify(obj));
console.log(copy) // {a: 0, b: {…}, f: "2018-12-07T08:11:48.210Z"}

複製代碼
  • NODE.JS中的深度複製
  • 從8.0.0版開始,Node.js提供了與結構化克隆兼容的序列化API。
  • 對於低於8.0.0的版本或更穩定的實現,能夠使用lodash的cloneDeep方法,該方法也基於結構化克隆算法。
const v8 = require('v8');
const buf = v8.serialize({a: 'foo', b: new Date()});
const cloned = v8.deserialize(buf);
cloned.b.getMonth();
複製代碼

小結

  • 總而言之,在Javascript中複製對象的最佳算法在很大程度上取決於您要複製的對象的上下文和類型。雖然lodash是通用深層複製功能最安全的選擇,咱們也能夠動手寫一個簡單的適用日期拷貝的深度拷貝。
  • 適用日期的深拷貝實現-示例
function deepClone(obj) {
  var copy;

  // Handle the 3 simple types, and null or undefined
  if (null == obj || "object" != typeof obj) return obj;

  // Handle Date
  if (obj instanceof Date) {
    copy = new Date();
    copy.setTime(obj.getTime());
    return copy;
  }

  // Handle Array
  if (obj instanceof Array) {
    copy = [];
    for (var i = 0, len = obj.length; i < len; i++) {
        copy[i] = deepClone(obj[i]);
    }
    return copy;
  }

  // Handle Function
  if (obj instanceof Function) {
    copy = function() {
      return obj.apply(this, arguments);
    }
    return copy;
  }

  // Handle Object
  if (obj instanceof Object) {
      copy = {};
      for (var attr in obj) {
          if (obj.hasOwnProperty(attr)) copy[attr] = deepClone(obj[attr]);
      }
      return copy;
  }

  throw new Error("Unable to copy obj as type isn't supported " + obj.constructor.name);
}
複製代碼

參考連接

相關文章
相關標籤/搜索