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