摘要:對象的淺拷貝淺拷貝是對象共用一個內存地址,對象的變化相互影響。這是特別值得注意的地方。和能正確處理的對象只有等能夠被表示的數據結構,因此函數這種不能被表示的類型將不能被正確處理。
對象的淺拷貝:
淺拷貝是對象共用一個內存地址,對象的變化相互影響。比如常見的賦值引用就是淺拷貝:
let srcObj = {"name": "lilei", "age": "20"}; let copyObj = srcObj; copyObj.age = "22"; console.log("srcObj", srcObj); // srcObj { name: "lilei", age: "22" } console.log("copyObj", copyObj); // copyObj { name: "lilei", age: "22" }對象的深拷貝:
簡單理解深拷貝是將對象放到一個新的內存中,兩個對象的改變不會相互影響。
Object.assign()MDN上這樣介紹Object.assign(),"Object.assign() 方法用于將所有可枚舉的屬性的值從一個或多個源對象復制到目標對象。它將返回目標對象",好吧,并看不出是深拷貝還是淺拷貝,我們來測試一下
let srcObj = {"name": "lilei", "age": "20"}; let copyObj2 = Object.assign({}, srcObj, {"age": "21"}); copyObj2.age = "23"; console.log("srcObj", srcObj); //{ name: "lilei", age: "22" }
看起來好像是深拷貝了,那其實這里let copyObj2 = Object.assign({}, srcObj, {"age": "21"}); 我們把srcObj 給了一個新的空對象。同樣目標對象為 {},我們再來測試下:
srcObj = {"name": "明", grade: {"chi": "50", "eng": "50"} }; copyObj2 = Object.assign({}, srcObj); copyObj2.name = "紅"; copyObj2.grade.chi = "60"; console.log("新 objec srcObj", srcObj); // { name: "明", grade: { chi: "60", eng: "50" } }
從例子中可以看出,改變復制對象的name 和 grade.chi ,源對象的name沒有變化,但是grade.chi卻被改變了。因此我們可以看出Object.assign()拷貝的只是屬性值,假如源對象的屬性值是一個指向對象的引用,它也只拷貝那個引用值。
也就是說,對于Object.assign()而言, 如果對象的屬性值為簡單類型(string, number),通過Object.assign({},srcObj);得到的新對象為‘深拷貝’;如果屬性值為對象或其它引用類型,那對于這個對象而言其實是淺拷貝的。這是Object.assign()特別值得注意的地方。
多說一句,Object.assign({}, src1, src2); 對于scr1和src2之間相同的屬性是直接覆蓋的,如果屬性值為對象,是不會對對象之間的屬性進行合并的。
有很多第三方庫實現了對象的深拷貝,比如常見的 Jquery 和 underscore ,比較未來的 lodash,實現源碼還沒仔細分析,分析之后再來補充。
不過,如果你沒有引入這些庫,對于深拷貝還有一個簡單的方法實現
JSON.parse() 和 JSON.stringify() 算是對 深拷貝的一個無腦實現,看例子:
srcObj = {"name": "明", grade: {"chi": "50", "eng": "50"} }; // copyObj2 = Object.assign({}, srcObj); copyObj2 = JSON.parse(JSON.stringify(srcObj)); copyObj2.name = "紅"; copyObj2.grade.chi = "60"; console.log("JSON srcObj", srcObj); // { name: "明", grade: { chi: "50", eng: "50" } }
可以看到改變copyObj2并沒有改變原始對象,實現了基本的深拷貝。
但是用JSON.parse()和JSON.stringify()會有一個問題。
JSON.parse()和JSON.stringify()能正確處理的對象只有Number、String、Array等能夠被json表示的數據結構,因此函數這種不能被json表示的類型將不能被正確處理。比如
srcObj = {"name": "明", grade: {"chi": "50", "eng": "50"}, "hello": function() {console.log("hello")}}; // copyObj2 = Object.assign({}, srcObj); copyObj2 = JSON.parse(JSON.stringify(srcObj)); copyObj2.name = "紅"; copyObj2.grade.chi = "60"; console.log("JSON srcObj", copyObj2); //{ name: "紅", grade: { chi: "60", eng: "50" } }
可以看出,經過轉換之后,function丟失了,因此JSON.parse()和JSON.stringify()還是需要謹慎使用。
后續再補充深拷貝實現思想。。。。
數組的深拷貝和淺拷貝最后在補充一點數組的深拷貝和淺拷貝,同對象一樣數組的淺拷貝也是改變其中一個會相互影響,比如:
let srcArr = [1, 2, 3]; let copyArr = srcArr; copyArr[0] = "0"; console.log("srcArr", srcArr); // ["0", 2, 3]
但是數組的深拷貝方法要相對簡單一些可以理解為數組方法中那些會改變原數組的方法,比如
concat
slice
es6 的Array.from
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/93871.html
摘要:它將返回目標對象。有些文章說是深拷貝,其實這是不正確的。深拷貝相比于淺拷貝速度較慢并且花銷較大。拷貝前后兩個對象互不影響。使用深拷貝的場景完全改變變量之后對沒有任何影響,這就是深拷貝的魔力。 一、賦值(Copy) 賦值是將某一數值或對象賦給某個變量的過程,分為: 1、基本數據類型:賦值,賦值之后兩個變量互不影響 2、引用數據類型:賦址,兩個變量具有相同的引用,指向同一個對象,相互之間有...
摘要:原文地址淺拷貝和深拷貝只針對像這樣的復雜對象的簡單來說,淺拷貝只拷貝一層對象的屬性,而深拷貝則遞歸拷貝了所有層級。淺拷貝通過來實現淺拷貝。 原文地址:http://www.silenceboy.com/201... 淺拷貝和深拷貝只針對像Object, Array這樣的復雜對象的.簡單來說,淺拷貝只拷貝一層對象的屬性,而深拷貝則遞歸拷貝了所有層級。 淺拷貝 通過 Object.ass...
摘要:引用類型值引用類型值是保存在堆內存中的對象,變量保存的只是指向該內存的地址,在復制引用類型值的時候,其實只復制了指向該內存的地址。 前言 要理解 JavaScript中淺拷貝和深拷貝的區別,首先要明白JavaScript的數據類型。JavaScript有兩種數據類型,基礎數據類型和引用數據類型。js的基本類型:undefined,null,string,boolean,number,s...
摘要:引用數據類型是存放在堆內存中的,變量實際上是一個存放在棧內存的指針,這個指針指向堆內存中的地址。棧和堆的區別其實淺拷貝和深拷貝的主要區別就是數據在內存中的存儲類型不同。這里,對存在子對象的對象進行拷貝的時候,就是深拷貝了。 數據類型 在開始拷貝之前,我們從JavaScript的數據類型和內存存放地址講起。數據類型分為基本數據類型 和引用數據類型 基本數據類型主要包括undefin...
摘要:基本類型指的是簡單的數據段,而引用類型指的是一個對象保存在堆內存中的地址,不允許我們直接操作內存中的地址,也就是說不能操作對象的內存空間,所以,我們對對象的操作都只是在操作它的引用而已。 工作中經常會遇到需要復制 JavaScript 數據的時候,遇到 bug 時實在令人頭疼;面試中也經常會被問到如何實現一個數據的深淺拷貝,但是你對其中的原理清晰嗎?一起來看一下吧! 一、為什么會有深淺...
閱讀 2227·2021-11-15 11:39
閱讀 982·2021-09-26 09:55
閱讀 925·2021-09-04 16:48
閱讀 2831·2021-08-12 13:23
閱讀 919·2021-07-30 15:30
閱讀 2455·2019-08-29 14:16
閱讀 886·2019-08-26 10:15
閱讀 525·2019-08-23 18:40