JS的深拷貝和淺拷貝

來源:互聯網
上載者:User

標籤:深拷貝   應該   log   source   simple   是什麼   lse   拷貝   tor   

淺析:淺拷貝是拷貝一層,深層次的對象層級的就拷貝引用;深拷貝是拷貝多層,每一層級的資料都會拷貝出來;

總結:淺拷貝的時候如果資料是基礎資料型別 (Elementary Data Type),那麼就如同直接賦值那種,會拷貝其本身,如果除了基礎資料型別 (Elementary Data Type)之外還有一層對象,那麼對於淺拷貝而言就只能拷貝其引用,對象的改變會反應到拷貝對象上;但是深拷貝就會拷貝多層,即使是嵌套了對象,也會都拷貝出來。

淺拷貝的實現方式

實現淺拷貝的第一種方法

var obj = {  a: "hello",  b:{    a: "world",    b: 21  },  c:["Bob", "Tom", "Jenny"],  d:function() {    alert("hello world");  }};function simpleClone(initalObj) {  var obj = {};  for ( var i in initalObj) {    obj[i] = initalObj[i];  }  return obj;}var cloneObj = simpleClone(obj); console.log(cloneObj.a);console.log(cloneObj.b);console.log(cloneObj.c);console.log(cloneObj.d); //更改原對象中的a,b,c,d,看看拷貝過來的對象是否變化cloneObj.a = "changed";cloneObj.b.a = "changed";cloneObj.b.b = 25;cloneObj.c = [1, 2, 3];cloneObj.d = function() { alert("changed"); };console.log(obj.a);    //helloconsole.log(obj.b);    //{a:"changed",b:25},事實上就是只有對象是拷貝的參考型別console.log(obj.c);    //[‘Bob‘,‘Tom‘,‘Jenny‘]console.log(obj.d);    //...alert("hello world")

淺拷貝就是拷貝了一層,除了對象是拷貝的參考型別,其他都是直接將值傳遞,有自己的記憶體空間的

實現淺拷貝的第二種方法

ES6中的Object.assign方法,Object.assign是ES6的新函數。Object.assign() 方法可以把任意多個的來源物件自身的可枚舉屬性拷貝給目標對象,然後返回目標對象。但是 Object.assign() 進行的是淺拷貝,拷貝的是對象的屬性的引用,而不是對象本身。

Object.assign(target, ...sources)

參數:

target:目標對象。
sources:任意多個來源物件。
傳回值:目標對象會被返回。

var obj1 = {  a: "hello",  b: {    a: "hello",    b: 21  }}; var cloneObj1= Object.assign({}, obj1);cloneObj1.a = "changed";cloneObj1.b.a = "changed";console.log(obj1.a);  //helloconsole.log(obj.b.a); // "changed"
深拷貝的實現方式

1、手動複製

把一個對象的屬性複製給另一個對象的屬性

var obj1 = { a: 10, b: 20, c: 30 };var obj2 = { a: obj1.a, b: obj1.b, c: obj1.c };obj2.b = 100;console.log(obj1);// { a: 10, b: 20, c: 30 } <-- 沒被改到console.log(obj2);// { a: 10, b: 100, c: 30 }

2、對象只有一層的話可以使用上面的:Object.assign()函數

Object.assign({}, obj1)的意思是先建立一個Null 物件{},接著把obj1中所有的屬性複製過去,所以obj2會長得跟obj1一樣,這時候再修改obj2.b也不會影響obj1。

因為Object.assign跟我們手動複製的效果相同,所以一樣只能處理深度只有一層的對象,沒辦法做到真正的 Deep Copy。不過如果要複製的對象只有一層的話可以考慮使用它。

3、轉成 JSON 再轉回來

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

var obj1 = { body: { a: 10 } };var obj2 = JSON.parse(JSON.stringify(obj1));obj2.body.a = 20;console.log(obj1);// { body: { a: 10 } } <-- 沒被改到console.log(obj2);// { body: { a: 20 } }console.log(obj1 === obj2);// falseconsole.log(obj1.body === obj2.body);// false

這樣做是真正的Deep Copy,這種方法簡單易用。

但是這種方法也有不少壞處,譬如它會拋棄對象的constructor。也就是深拷貝之後,不管這個對象原來的建構函式是什麼,在深拷貝之後都會變成Object。

這種方法能正確處理的對象只有 Number, String, Boolean, Array, 扁平對象,即那些能夠被 json 直接表示的資料結構。RegExp對象是無法通過這種方式深拷貝。

也就是說,只有可以轉成JSON格式的對象才可以這樣用,像function沒辦法轉成JSON。

4、遞迴拷貝

function deepClone(initalObj, finalObj) {      var obj = finalObj || {};      for (var i in initalObj) {            if (typeof initalObj[i] === ‘object‘) {      obj[i] = (initalObj[i].constructor === Array) ? [] : {};                  arguments.callee(initalObj[i], obj[i]);    } else {      obj[i] = initalObj[i];    }  }      return obj;}var str = {};var obj = { a: {a: "hello", b: 21} };deepClone(obj, str);console.log(str.a);

上述代碼確實可以實現深拷貝。但是當遇到兩個互相引用的對象,會出現死迴圈的情況。

為了避免相互引用的對象導致死迴圈的情況,則應該在遍曆的時候判斷是否相互引用對象,如果是則退出迴圈。

改進版代碼如下:

function deepClone(initalObj, finalObj) {      var obj = finalObj || {};      for (var i in initalObj) {            var prop = initalObj[i];        // 避免相互引用對象導致死迴圈,如initalObj.a = initalObj的情況    if(prop === obj) {                  continue;    }            if (typeof prop === ‘object‘) {      obj[i] = (prop.constructor === Array) ? [] : {};                  arguments.callee(prop, obj[i]);    } else {      obj[i] = prop;    }  }      return obj;}var str = {};var obj = { a: {a: "hello", b: 21} };deepClone(obj, str);console.log(str.a);

5、使用Object.create()方法

直接使用var newObj = Object.create(oldObj),可以達到深拷貝的效果。

function deepClone(initalObj, finalObj) {      var obj = finalObj || {};      for (var i in initalObj) {            var prop = initalObj[i];        // 避免相互引用對象導致死迴圈,如initalObj.a = initalObj的情況    if(prop === obj) {                  continue;    }            if (typeof prop === ‘object‘) {      obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);    } else {      obj[i] = prop;    }  }      return obj;}

.

JS的深拷貝和淺拷貝

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.