js深拷貝與淺拷貝一文徹底搞懂
深拷貝淺拷貝只是針對(duì)引用數(shù)據(jù)類型
JavaScript數(shù)據(jù)類型包括基本數(shù)據(jù)類型(Number,String,boolean,Null,Undefined,Symbol)、引用數(shù)據(jù)類型(Array,Object)
基本數(shù)據(jù)類型的特點(diǎn):直接存儲(chǔ)在棧(stack)中的數(shù)據(jù)
引用數(shù)據(jù)類在棧中存有指針,實(shí)體數(shù)據(jù)存在堆中,通過(guò)棧中的指針找到堆中的引用數(shù)據(jù)類型的實(shí)體
淺拷貝只復(fù)制指向某個(gè)對(duì)象的指針,而不復(fù)制對(duì)象本身,新舊對(duì)象還是共享同一塊內(nèi)存。但深拷貝會(huì)另外創(chuàng)造一個(gè)一模一樣的對(duì)象,新對(duì)象跟原對(duì)象不共享內(nèi)存,修改新對(duì)象不會(huì)改到原對(duì)象。
賦值和淺拷貝的區(qū)別
當(dāng)我們把一個(gè)對(duì)象賦值給一個(gè)新的變量時(shí),賦的其實(shí)是該對(duì)象的在棧中的地址,而不是堆中的數(shù)據(jù)。也就是兩個(gè)對(duì)象指向的是同一個(gè)存儲(chǔ)空間,無(wú)論哪個(gè)對(duì)象發(fā)生改變,其實(shí)都是改變的存儲(chǔ)空間的內(nèi)容,因此,兩個(gè)對(duì)象是聯(lián)動(dòng)的。
淺拷貝是按位拷貝對(duì)象,它會(huì)創(chuàng)建一個(gè)新對(duì)象,這個(gè)對(duì)象有著原始對(duì)象屬性值的一份精確拷貝。如果屬性是基本類型,拷貝的就是基本類型的值;如果屬性是內(nèi)存地址(引用類型),拷貝的就是內(nèi)存地址 ,因此如果其中一個(gè)對(duì)象改變了這個(gè)地址,就會(huì)影響到另一個(gè)對(duì)象。即默認(rèn)拷貝構(gòu)造函數(shù)只是對(duì)對(duì)象進(jìn)行淺拷貝復(fù)制(逐個(gè)成員依次拷貝),即只復(fù)制對(duì)象空間而不復(fù)制資源。
// 對(duì)象賦值 var obj1 = { 'name' : 'zhangsan', 'age' : '18', 'language' : [1,[2,3],[4,5]], }; var obj2 = obj1; obj2.name = "lisi"; obj2.language[1] = ["二","三"]; console.log('obj1',obj1) console.log('obj2',obj2)
// 淺拷貝 var obj1 = { 'name' : 'zhangsan', 'age' : '18', 'language' : [1,[2,3],[4,5]], }; var obj3 = shallowCopy(obj1); obj3.name = "lisi"; obj3.language[1] = ["二","三"]; function shallowCopy(src) { var dst = {}; for (var prop in src) { if (src.hasOwnProperty(prop)) { dst[prop] = src[prop]; } } return dst; } console.log('obj1',obj1) console.log('obj3',obj3)
上面例子中,obj1是原始數(shù)據(jù),obj2是賦值操作得到,而obj3淺拷貝得到。我們可以很清晰看到對(duì)原始數(shù)據(jù)的影響,具體請(qǐng)看下表:
淺拷貝的實(shí)現(xiàn)方法
1. Object.assign()
Object.assign() 方法可以把任意多個(gè)的源對(duì)象自身的可枚舉屬性拷貝給目標(biāo)對(duì)象,然后返回目標(biāo)對(duì)象。但是 Object.assign() 進(jìn)行的是淺拷貝,拷貝的是對(duì)象的屬性的引用,而不是對(duì)象本身。
對(duì)于Object.assign()而言,如果對(duì)象的屬性值為簡(jiǎn)單類型(string,number),通過(guò)Object.assign({},srcobj);得到的新對(duì)象為深拷貝;如果屬性值為對(duì)象或其他引用類型,那對(duì)于這個(gè)對(duì)象而言其實(shí)是淺拷貝
2. Array.prototype.concat()
let arr = [1, 3, { username: 'kobe' }]; let arr2=arr.concat(); arr2[2].username = 'wade'; console.log(arr);
3. Array.prototype.slice()
let arr = [1, 3, { username: ' kobe' }]; let arr3 = arr.slice(); arr3[2].username = 'wade' console.log(arr);
深拷貝的實(shí)現(xiàn)
1. JSON.parse(JSON.stringify())
原理: 用JSON.stringify將對(duì)象轉(zhuǎn)成JSON字符串,再用JSON.parse()把字符串解析成對(duì)象,一去一來(lái),新的對(duì)象產(chǎn)生了,而且對(duì)象會(huì)開(kāi)辟新的棧,實(shí)現(xiàn)深拷貝。
這種方法雖然可以實(shí)現(xiàn)數(shù)組或?qū)ο笊羁截?,但不能處理函?shù)。
這是因?yàn)?JSON.stringify() 方法是將一個(gè)JavaScript值(對(duì)象或者數(shù)組)轉(zhuǎn)換為一個(gè) JSON字符串,不能接受函數(shù)。
2. 手寫遞歸方法
//遞歸來(lái)實(shí)現(xiàn)深拷貝 function deepClone(obj){ var newObj = obj instanceof Array ? []:{}; if(typeof obj !== 'object'){ return obj; }else { for(var i in obj) { newObj[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i]; } } return newObj; } var q = [1, 2, 4, 6, { age: 12 }, [1, 2]]; var d = deepClone(q) console.log(d)
3. 函數(shù)庫(kù)lodash
var _ = require('lodash'); var obj1 = { a: 1, b: { f: { g: 1 } }, c: [1, 2, 3] }; var obj2 = _.cloneDeep(obj1); console.log(obj1.b.f === obj2.b.f); // false
更多關(guān)于js深拷貝與淺拷貝的文章請(qǐng)查看下面的相關(guān)鏈接
相關(guān)文章
js正則表達(dá)式最長(zhǎng)匹配(貪婪匹配)和最短匹配(懶惰匹配)用法分析
這篇文章主要介紹了js正則表達(dá)式最長(zhǎng)匹配(貪婪匹配)和最短匹配(懶惰匹配)用法,結(jié)合實(shí)例形式分析了貪婪匹配與懶惰匹配的具體用法與相關(guān)注意事項(xiàng),需要的朋友可以參考下2016-12-12JavaScript制作簡(jiǎn)單網(wǎng)頁(yè)計(jì)算器
這篇文章主要為大家詳細(xì)介紹了JavaScript制作簡(jiǎn)單網(wǎng)頁(yè)計(jì)算器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08JavaScript中通用的jquery動(dòng)畫滾屏實(shí)例
這篇文章主要介紹了JavaScript中通用的jquery動(dòng)畫滾屏實(shí)例,本文通過(guò)實(shí)際代碼來(lái)詳解實(shí)現(xiàn)方法,需要的朋友可以參考一下2022-07-07Javascript(AJAX)解析XML的代碼(兼容FIREFOX/IE)
Javascript AJAX 解析XML的代碼(兼容FIREFOX/IE)2010-07-07關(guān)于UTF-8的客戶端用AJAX方式獲取GB2312的服務(wù)器端亂碼問(wèn)題的解決辦法
客戶端是UTF-8編碼,這也是現(xiàn)在大家公認(rèn)的標(biāo)準(zhǔn)編碼在這種情況下,實(shí)用AJAX異步獲取GB2312編碼的服務(wù)器端信息時(shí),不可避免的要遇到漢字亂碼問(wèn)題2010-11-11html判斷當(dāng)前頁(yè)面是否在iframe中的實(shí)例
下面小編就為大家?guī)?lái)一篇html判斷當(dāng)前頁(yè)面是否在iframe中的實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-11-11