摘要:一篇文章徹底說清的深拷貝淺拷貝這篇文章的受眾第一類業(yè)務(wù)需要急需知道如何深拷貝對象的開發(fā)者。這篇文章分享的目的更多還是希望用一篇文章整理清楚深淺拷貝的含義遞歸實(shí)現(xiàn)思路以及小伙伴們?nèi)绻褂昧诉@種黑科技一定要清楚這樣寫的優(yōu)缺點(diǎn)。
一篇文章徹底說清JS的深拷貝and淺拷貝 這篇文章的受眾
第一類,業(yè)務(wù)需要,急需知道如何深拷貝JS對象的開發(fā)者。
第二類,希望扎實(shí)JS基礎(chǔ),將來好去面試官前秀操作的好學(xué)者。
寫給第一類讀者你只需要一行黑科技代碼就可以實(shí)現(xiàn)深拷貝
var copyObj = { name: "ziwei", arr : [1,2,3] } var targetObj = JSON.parse(JSON.stringify(copyObj)) 此時(shí) copyObj.arr !== targetObj.arr 已經(jīng)實(shí)現(xiàn)了深拷貝
別著急走,利用window.JSON的方法做深拷貝存在2個(gè)缺點(diǎn):
如果你的對象里有函數(shù),函數(shù)無法被拷貝下來
無法拷貝copyObj對象原型鏈上的屬性和方法
當(dāng)然,你明確知道他們的缺點(diǎn)后,如果他的缺點(diǎn)對你的業(yè)務(wù)需求沒有影響,就可以放心使用了,一行原生代碼就能搞定。
目前我在開發(fā)業(yè)務(wù)場景中,大多還真可以忽略上面2個(gè)缺點(diǎn)。往往需要深拷貝的對象里沒有函數(shù),也不需要拷貝它原型鏈的屬性。
寫給第二類讀者下面我會盡可能全面的講解清楚JS里對象的拷貝,要講清楚拷貝,你需要一點(diǎn)點(diǎn)前置知識
你需要的前置知識:
理解JS里的引用類型和值類型的區(qū)別,知道Obj存儲的只是引用
對原型鏈有基本了解
關(guān)于對象拷貝的全部:
1.深拷貝、淺拷貝是什么
2.深拷貝、淺拷貝在業(yè)務(wù)里的最常見的應(yīng)用場景
3.深拷貝和淺拷貝的實(shí)現(xiàn)方式
4.總結(jié)與建議
1.深拷貝、淺拷貝是什么我們討論JS對象深拷貝、淺拷貝的前提
只有對象里嵌套對象的情況下,才會根據(jù)需求討論,我們要深拷貝還是淺拷貝。
比如下面這種對象
var obj1 = { name: "ziwei", arr : [1,2,3] }
因?yàn)?如果是類似這樣{name: "ziwei"},沒有嵌套對象的對象的話,就沒必要區(qū)分深淺拷貝了。只有在有嵌套的對象時(shí),深拷貝和淺拷貝才有區(qū)別
淺拷貝是什么樣子的 (我們暫時(shí)不管具體如何實(shí)現(xiàn),因?yàn)橄旅鏁沃v)
調(diào)用shallowCopy()后,obj2拷貝obj1所有的屬性。但是obj2.arr和obj1.arr是不同的引用,指向同一個(gè)內(nèi)存空間
var obj2 = shallowCopy( obj1 , {}) console.log( obj1 !== obj2 ) // true 無論哪種拷貝,obj1和obj2一定都是2個(gè)不同的對象(內(nèi)存空間不同) console.log( obj2.arr === obj1.arr ) // true 他們2個(gè)對象里arr的引用,指向【相同的】內(nèi)存空間
所以, 2個(gè)obj經(jīng)過拷貝后,雖然他們屬性相同,也的確是不同的對象,但他們內(nèi)部的obj都是指向同一個(gè)內(nèi)存空間,這種我們叫淺拷貝
深拷貝是什么樣子的 (我們暫時(shí)不管具體如何實(shí)現(xiàn),因?yàn)橄旅鏁沃v)
調(diào)用deepCopy()后,obj2拷貝obj1所有的屬性,而且obj2.arr和obj1.arr是指向不同的內(nèi)存空間,
2個(gè)obj2除了拷貝了一樣的屬性,沒有任何其他關(guān)聯(lián)。
var obj2 = deepCopy( obj1 , {}) console.log( obj1 !== obj2 ) // true 無論哪種拷貝,obj1和obj2一定都是2個(gè)不同的對象(內(nèi)存空間不同) console.log( obj2.arr === obj1.arr ) // false 他們2個(gè)對象里arr的引用,指向【不同的】內(nèi)存空間
所以, 2個(gè)obj經(jīng)過拷貝后,除了拷貝下來相同的屬性之外,沒有任何其他關(guān)聯(lián)的2個(gè)對象,這種我們叫深拷貝
2.深拷貝在業(yè)務(wù)里的最常見的應(yīng)用場景舉個(gè)栗子,業(yè)務(wù)需求是 : 一個(gè)表格展示商品各種信息,點(diǎn)擊【同意】時(shí),是可以彈出對話框調(diào)整商品數(shù)量的。
這種業(yè)務(wù)需求下,我們就會用到對象的深拷貝。因?yàn)椤旧唐繁砀瘛康膶傩院汀菊{(diào)整商品表格】的屬性幾乎一樣,我們需要拷貝。
下面的偽代碼和圖片就是展示使用淺拷貝存在的問題
這樣得到的adjustTableArr和tableArr里,內(nèi)部對象都是相同的,所以就出現(xiàn)了圖中紅線標(biāo)注的情況,
當(dāng)我們修改【調(diào)整商品表格】里的商品數(shù)量時(shí),【商品表格】也跟著改變了,這并不是我們想要的
// 表格對象的數(shù)據(jù)結(jié)構(gòu) var tableArr = [ {goods_name : "長袖腰背夾" , code : "M216C239E0864" , num : "2"}, {goods_name : "長袖腰背夾" , code : "M216C240B0170" , num : "3"}, {goods_name : "短塑褲" , code : "M216D241C04106" , num : "3"}, ] var adjustTableArr = [] // 調(diào)整表格用的數(shù)組 for (var key in tableArr) { // 淺拷貝 adjustTableArr[key] = tableArr[key] }
而實(shí)際上,我們希望這2個(gè)表格里的數(shù)據(jù)完全獨(dú)立,互不干擾,只有在確認(rèn)調(diào)整之后才刷新商品數(shù)量。
這種情況下我們就可以使用前面說的深拷貝的一行黑科技
var adjustTableArr = JSON.parse(JSON.stringify(tableArr))
還記得它的缺陷嗎? 對象里的函數(shù)無法被拷貝,原型鏈里的屬性無法被拷貝。這里就對業(yè)務(wù)沒有影響,可以很方便的深拷貝。
3.深拷貝和淺拷貝的實(shí)現(xiàn)方式其實(shí)JQ里已經(jīng)有$.extend()函數(shù),實(shí)現(xiàn)就是深拷貝和淺拷貝的功能。有興趣的小伙伴也可以看看源碼。
淺拷貝
淺拷貝比較簡單,就是用for in 循環(huán)賦值
function shallowCopy(source, target = {}) { var key; for (key in source) { if (source.hasOwnProperty(key)) { // 意思就是__proto__上面的屬性,我不拷貝 target[key] = source[key]; } } return target; }
深拷貝的實(shí)現(xiàn)
深拷貝,就是遍歷那個(gè)被拷貝的對象
判斷對象里每一項(xiàng)的數(shù)據(jù)類型
如果不是對象類型,就直接賦值,如果是對象類型,就再次調(diào)用deepCopy,遞歸的去賦值。
function deepCopy(source, target = {}) { var key; for (key in source) { if (source.hasOwnProperty(key)) { // 意思就是__proto__上面的屬性,我不拷貝 if (typeof(source[key]) === "object") { // 如果這一項(xiàng)是object類型,就遞歸調(diào)用deepCopy target[key] = Array.isArray(source[key]) ? [] : {}; deepCopy(source[key], target[key]); } else { // 如果不是object類型,就直接賦值拷貝 target[key] = source[key]; } } } return target; }
以上的無論深、淺拷貝,都用了source.hasOwnProperty(key),意思是判斷這一項(xiàng)是否是其自有屬性,是的話才拷貝,不是就不拷貝。
也就是說__proto__上面的屬性,我不拷貝。這個(gè)其實(shí)你可以根據(jù)業(yè)務(wù)需求,來決定加上和這個(gè)條件
(JQ的$.extend()是會連__proto__上的屬性也拷貝下來的,但是是直接拷貝到對象上,而不是放到之前的__proto__上)
4.總結(jié)與建議雖然大家可能經(jīng)常用框架提供的api來實(shí)現(xiàn)深拷貝。
這篇文章分享的目的,更多還是希望用一篇文章整理清楚深淺拷貝的含義、遞歸實(shí)現(xiàn)思路,以及小伙伴們?nèi)绻褂昧薐SON.parse()這種黑科技,一定要清楚這樣寫的優(yōu)缺點(diǎn)。
5.修正上面的deepCopy方法有漏洞,沒有考慮source一開始就是數(shù)組的情況
下面是一個(gè)修改后版本
function deepCopy( source ) { let target = Array.isArray( source ) ? [] : {} for ( var k in source ) { if ( typeof source[ k ] === "object" ) { target[ k ] = deepCopy( source[ k ] ) } else { target[ k ] = source[ k ] } } return target }
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/112992.html
摘要:一篇文章徹底說清的深拷貝淺拷貝這篇文章的受眾第一類業(yè)務(wù)需要急需知道如何深拷貝對象的開發(fā)者。這篇文章分享的目的更多還是希望用一篇文章整理清楚深淺拷貝的含義遞歸實(shí)現(xiàn)思路以及小伙伴們?nèi)绻褂昧诉@種黑科技一定要清楚這樣寫的優(yōu)缺點(diǎn)。 一篇文章徹底說清JS的深拷貝and淺拷貝 這篇文章的受眾 第一類,業(yè)務(wù)需要,急需知道如何深拷貝JS對象的開發(fā)者。 第二類,希望扎實(shí)JS基礎(chǔ),將來好去面試官前秀操作...
摘要:一篇文章徹底說清的深拷貝淺拷貝這篇文章的受眾第一類業(yè)務(wù)需要急需知道如何深拷貝對象的開發(fā)者。這篇文章分享的目的更多還是希望用一篇文章整理清楚深淺拷貝的含義遞歸實(shí)現(xiàn)思路以及小伙伴們?nèi)绻褂昧诉@種黑科技一定要清楚這樣寫的優(yōu)缺點(diǎn)。 一篇文章徹底說清JS的深拷貝and淺拷貝 這篇文章的受眾 第一類,業(yè)務(wù)需要,急需知道如何深拷貝JS對象的開發(fā)者。 第二類,希望扎實(shí)JS基礎(chǔ),將來好去面試官前秀操作...
摘要:案例中的賦值就是典型的淺拷貝,并且深拷貝與淺拷貝的概念只存在于引用類型。修改修改經(jīng)測試,也只能實(shí)現(xiàn)一維對象的深拷貝。經(jīng)過驗(yàn)證,我們發(fā)現(xiàn)提供的自有方法并不能徹底解決的深拷貝問題。 在說深拷貝與淺拷貝前,我們先看兩個(gè)簡單的案例: //案例1 var num1 = 1, num2 = num1; console.log(num1) //1 console.log(num2) //1 num...
摘要:而引用類型值是指那些保存堆內(nèi)存中的對象,意思是變量中保存的實(shí)際上只是一個(gè)指針,這個(gè)指針指向內(nèi)存中的另一個(gè)位置,該位置保存對象。而堆內(nèi)存主要負(fù)責(zé)對象這種變量類型的存儲。我們需要明確一點(diǎn),深拷貝與淺拷貝的概念只存在于引用類型。 深拷貝和淺拷貝 說起深拷貝和淺拷貝,首先我們來看兩個(gè)栗子 // 栗子1 var a = 1,b=a; console.log(a); console.log(b) ...
摘要:引用類型值指的是那些保存在堆內(nèi)存中的對象,所以引用類型的值保存的是一個(gè)指針,這個(gè)指針指向存儲在堆中的一個(gè)對象。因此當(dāng)操作結(jié)束后,這兩個(gè)變量實(shí)際上指向的是同一個(gè)在堆內(nèi)存中的對象,改變其中任意一個(gè)對象,另一個(gè)對象也會跟著改變。 一、為什么有深拷貝和淺拷貝? ???? 這個(gè)要從js中的數(shù)據(jù)類型說起,js中數(shù)據(jù)類型分為基本數(shù)據(jù)類型和引用數(shù)據(jù)類型。 ????基本類型值指的是那些保存在棧內(nèi)存中的簡...
閱讀 2646·2021-11-23 09:51
閱讀 914·2021-09-24 10:37
閱讀 3631·2021-09-02 15:15
閱讀 1973·2019-08-30 13:03
閱讀 1894·2019-08-29 15:41
閱讀 2640·2019-08-29 14:12
閱讀 1437·2019-08-29 11:19
閱讀 3313·2019-08-26 13:39