Javascript中深拷貝的原理是什么,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
成都創(chuàng)新互聯(lián)服務項目包括岷縣網(wǎng)站建設、岷縣網(wǎng)站制作、岷縣網(wǎng)頁制作以及岷縣網(wǎng)絡營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關系等,向廣大中小型企業(yè)、政府機構等提供互聯(lián)網(wǎng)行業(yè)的解決方案,岷縣網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟效益。目前,我們服務的客戶以成都為中心已經(jīng)輻射到岷縣省份的部分城市,未來相信會繼續(xù)擴大服務區(qū)域并繼續(xù)獲得客戶的支持與信任!
為啥要用深拷貝?
在很多情況下,我們都需要給變量賦值,給內存地址賦予一個值,但是在賦值引用值類型的時候,只是共享一個內存區(qū)域,導致賦值的時候,還跟之前的值保持一直性。
看一個具體的例子
// 給test賦值了一個對象 var test = { a: 'a', b: 'b' }; // 將test賦值給test2 // 此時test和test2是共享了同一塊內存對象,這也就是淺拷貝 var test2 = test; test2.a = 'a2'; test.a === 'a2'// 為true
圖解:
這下就很好理解為什么引用值類型數(shù)據(jù)相互影響問題。
實現(xiàn)
實現(xiàn)一個深拷貝函數(shù),就不得不說javascript的數(shù)值類型。
判斷javascript類型
javascript中有以下基本類型
類型 | 描述 |
---|---|
undefined | undefined類型只有一個值undefined,它是變量未被賦值時的值 |
null | null類型也只有一個值null, 它是一個空的對象引用 |
Boolean | Boolean有兩種取值true和false |
String | 它表示文本信息 |
Number | 它表示數(shù)字信息 |
Object | 它是一系列屬性的無序集合, 包括函數(shù)Function和數(shù)組Array |
使用typeof是無法判斷function和array的,這里使用Object.prototype.toString方法。 默認情況下,每個對象都會從Object上繼承到toString()方法,如果這個方法沒有被這個對象自身或者更接近的上層原型上的同名方法覆蓋(遮蔽),則調用該對象的toString()方法時會返回”[object type]”,這里的字符串type表示了一個對象類型
function type(obj) { var toString = Object.prototype.toString; var map = { '[object Boolean]' : 'boolean', '[object Number]' : 'number', '[object String]' : 'string', '[object Function]' : 'function', '[object Array]' : 'array', '[object Date]' : 'date', '[object RegExp]' : 'regExp', '[object Undefined]': 'undefined', '[object Null]' : 'null', '[object Object]' : 'object' }; return map[toString.call(obj)]; }
實現(xiàn)deepClone
對于非引用值類型的數(shù)值,直接賦值,而對于引用值類型(object)還需要再次遍歷,遞歸賦值。
function deepClone(data) { var t = type(data), o, i, ni; if(t === 'array') { o = []; }else if( t === 'object') { o = {}; }else { return data; } if(t === 'array') { for (i = 0, ni = data.length; i < ni; i++) { o.push(deepClone(data[i])); } return o; }else if( t === 'object') { for( i in data) { o[i] = deepClone(data[i]); } return o; } }
這里有個點大家要注意下,對于function類型,博主這里是直接賦值的,還是共享一個內存值。這是因為函數(shù)更多的是完成某些功能,有個輸入值和返回值,而且對于上層業(yè)務而言更多的是完成業(yè)務功能,并不需要真正將函數(shù)深拷貝。
但是function類型要怎么拷貝呢?
其實博主只想到了用new來操作一下,但是function就會執(zhí)行一遍,不敢想象會有什么執(zhí)行結果哦!o(╯□╰)o!其它暫時還沒有什么好的想法,歡迎大家指導哦!
到這里差不多也就實現(xiàn)完了深拷貝,又有人覺的怎么沒有實現(xiàn)淺拷貝呢?
淺拷貝?
對于淺拷貝而言,可以理解為只操作一個共同的內存區(qū)域!這里會存在危險!(。﹏。*) 。
如果直接操作這個共享的數(shù)據(jù),不做控制的話,會經(jīng)常出現(xiàn)數(shù)據(jù)異常,被其它部分更改。所以應該不要直接操作數(shù)據(jù)源,給數(shù)據(jù)源封裝一些方法,來對數(shù)據(jù)來進行CURD操作。
到這里估計就差不多了,但是作為一個前端,不僅僅考慮javascript本身,還得考慮到dom、瀏覽器等。
Element類型
來看下面代碼,結果會返回啥呢?
Object.prototype.toString.call(document.getElementsByTagName('div')[0])
答案是[object HTMLDivElement]
有時候保存了dom元素, 一不小心進行深拷貝,上面的深拷貝函數(shù)就缺少了對Element元素的判斷。而判斷Element元素要使用instanceof來判斷。因為對于不同的標簽,tostring會返回對應不同的標簽的構造函數(shù)。
function type(obj) { var toString = Object.prototype.toString; var map = { '[object Boolean]' : 'boolean', '[object Number]' : 'number', '[object String]' : 'string', '[object Function]' : 'function', '[object Array]' : 'array', '[object Date]' : 'date', '[object RegExp]' : 'regExp', '[object Undefined]': 'undefined', '[object Null]' : 'null', '[object Object]' : 'object' }; if(obj instanceof Element) { return 'element'; } return map[toString.call(obj)]; }
其它方式?
JSON實現(xiàn)
先通過JSON.stringify一下,然后再JSON.parse一下,就能實現(xiàn)深拷貝。但是數(shù)據(jù)類型只支持基本數(shù)值類型。
var obj = { a: 'a', b: function(){console.log('b')} } //在JSON.stringify的時候就會把function給過濾了。 JSON.stringify(obj)// "{"a":"a"}"
關于Javascript中深拷貝的原理是什么問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關知識。