摘要:所以,深拷貝是對(duì)對(duì)象以及對(duì)象的所有子對(duì)象進(jìn)行拷貝實(shí)現(xiàn)方式就是遞歸調(diào)用淺拷貝對(duì)于深拷貝的對(duì)象,改變?cè)磳?duì)象不會(huì)對(duì)得到的對(duì)象有影響。
為什么會(huì)有淺拷貝與深拷貝
什么是淺拷貝與深拷貝
如何實(shí)現(xiàn)淺拷貝與深拷貝
好了,問(wèn)題出來(lái)了,那么下面就讓我們帶著這幾個(gè)問(wèn)題去探究一下吧!
如果文章中有出現(xiàn)紕漏、錯(cuò)誤之處,還請(qǐng)看到的小伙伴多多指教,先行謝過(guò)
以下↓
數(shù)據(jù)類型
在開始了解 淺拷貝 與 深拷貝 之前,讓我們先來(lái)回顧一下 JavaScript 的數(shù)據(jù)類型(可以參考這里 JavaScript中的數(shù)據(jù)類型)
在 JavaScript 中,我們將數(shù)據(jù)分為 基本數(shù)據(jù)類型(原始值) 與 引用類型
基本數(shù)據(jù)類型的值是按值訪問(wèn)的,基本類型的值是不可變的
引用類型的值是按引用訪問(wèn)的,引用類型的值是動(dòng)態(tài)可變的
由于數(shù)據(jù)類型的訪問(wèn)方式不同,它們的比較方式也是不一樣的
var a = 100; var b = 100; a === b // true var c = {a: 1, b: 2}; var d = {a: 1, b: 2}; c == d // false 兩個(gè)不同的對(duì)象
·基本數(shù)據(jù)類型的比較是值得比較
·引用類型的比較是引用地址的比較
鑒于以上數(shù)據(jù)類型的特點(diǎn),我們可以初步想到:所謂 淺拷貝 與 深拷貝 可能就是對(duì)于值的拷貝和引用的拷貝(簡(jiǎn)單數(shù)據(jù)類型都是對(duì)值的拷貝,不進(jìn)行區(qū)分)
一般來(lái)說(shuō),我們所涉及的拷貝對(duì)象,也都是針對(duì)引用類型的。由于引用類型屬性層級(jí)可能也會(huì)有多層,這樣也就引出了我們所要去了解的 淺拷貝 與 深拷貝
淺拷貝
顧名思義,所謂淺拷貝就是對(duì)對(duì)象進(jìn)行淺層次的復(fù)制,只復(fù)制一層對(duì)象的屬性,并不包括對(duì)象里面的引用類型數(shù)據(jù)
想象一下,如果讓你自己去實(shí)現(xiàn)這個(gè)功能,又會(huì)有怎么的思路呢
首先,我們需要知道被拷貝對(duì)象有哪些屬性吧,然后還需要知道這些屬性都對(duì)應(yīng)了那些值或者地址的引用吧。那么,答案已經(jīng)呼之欲出了,是的,循環(huán)
var person = { name: "tt", age: 18, friends: ["oo", "cc", "yy"] } function shallowCopy(source) { if (!source || typeof source !== "object") { throw new Error("error"); } var targetObj = source.constructor === Array ? [] : {}; for (var keys in source) { if (source.hasOwnProperty(keys)) { targetObj[keys] = source[keys]; } } return targetObj; } var p1 = shallowCopy(person); console.log(p1)
在上面的代碼中,我們創(chuàng)建了一個(gè) shallowCopy 函數(shù),它接收一個(gè)參數(shù)也就是被拷貝的對(duì)象。
首先創(chuàng)建了一個(gè)對(duì)象
然后 for...in 循環(huán)傳進(jìn)去的對(duì)象,為了避免循環(huán)到原型上面會(huì)被遍歷到的屬性,使用 hasOwnProperty 限制循環(huán)只在對(duì)象自身,將被拷貝對(duì)象的每一個(gè)屬性和值添加到創(chuàng)建的對(duì)象當(dāng)中
最后返回這個(gè)對(duì)象
通過(guò)測(cè)試,我們拿到了和 person 對(duì)象幾乎一致的對(duì)象 p1。看到這里,你是不是會(huì)想那這個(gè)結(jié)果和 var p1 = person 這樣的賦值操作又有什么區(qū)別呢?
我們?cè)賮?lái)測(cè)試一波
var p2 = person; // 這個(gè)時(shí)候我們修改person對(duì)象的數(shù)據(jù) person.name = "tadpole"; person.age = 19; person.friends.push("tt") p2.name // tadpole p2.age // 19 p2.friends // ["oo", "cc", "yy", "tt"] p1.name // tt p1.age // 18 p1.friends // ["oo", "cc", "yy", "tt"]
上面我們創(chuàng)建了一個(gè)新的變量 p2 ,將 person 賦值給 p2 ,然后比較兩個(gè)變量
深拷貝
了解完淺拷貝,相信小伙伴們對(duì)于深拷貝也應(yīng)該了然于胸了
淺拷貝由于只是復(fù)制一層對(duì)象的屬性,當(dāng)遇到有子對(duì)象的情況時(shí),子對(duì)象就會(huì)互相影響。所以,深拷貝是對(duì)對(duì)象以及對(duì)象的所有子對(duì)象進(jìn)行拷貝
實(shí)現(xiàn)方式就是遞歸調(diào)用淺拷貝
function deepCopy(source){ if(!source || typeof source !== "object"){ throw new Error("error"); } var targetObj = source.constructor === Array ? [] : {}; for(var keys in source){ if(source.hasOwnProperty(keys)){ if(source[keys] && typeof source[keys] === "object"){ targetObj[keys] = source[keys].constructor === Array ? [] : {}; targetObj[keys] = deepCopy(source[keys]); }else{ targetObj[keys] = source[keys]; } } } return targetObj; } var obj1 = { arr: [1, 2, 3], key: { id: 22 }, func: function() { console.log(123) } } var obj2 = deepCopy(obj1); obj1.arr.push(4); obj1.arr // [1, 2, 3, 4] obj2.arr // [1, 2, 3] obj1.key === obj2.key // false obj1.func === obj2.func // true
對(duì)于深拷貝的對(duì)象,改變?cè)磳?duì)象不會(huì)對(duì)得到的對(duì)象有影響。只是在拷貝的過(guò)程中源對(duì)象的方法丟失了,這是因?yàn)樵谛蛄谢?JavaScript 對(duì)象時(shí),所有函數(shù)和原型成員會(huì)被有意忽略
還有一種實(shí)現(xiàn)深拷貝的方式是利用 JSON 對(duì)象中的 parse 和 stringify,JOSN 對(duì)象中的 stringify 可以把一個(gè) js 對(duì)象序列化為一個(gè) JSON 字符串,parse 可以把 JSON 字符串反序列化為一個(gè) js 對(duì)象,通過(guò)這兩個(gè)方法,也可以實(shí)現(xiàn)對(duì)象的深復(fù)制
// 利用JSON序列化實(shí)現(xiàn)一個(gè)深拷貝 function deepCopy(source){ return JSON.parse(JSON.stringify(source)); } var o1 = { arr: [1, 2, 3], obj: { key: "value" }, func: function(){ return 1; } }; var o2 = deepCopy(o1); console.log(o2); // => {arr: [1,2,3], obj: {key: "value"}}
實(shí)現(xiàn)拷貝的其他方式
淺拷貝
·Array.prototype.slice()
·Array.prototype.concat()
·Object.assign
·拓展操作符...
...
深拷貝
很多框架或者庫(kù)都提供了深拷貝的方式,比如 jQuery 、 lodash 函數(shù)庫(kù)等等,基本實(shí)現(xiàn)方式也就和我們前面介紹的大同小異
后記
根據(jù)需求的不同,比如有時(shí)候我們需要一個(gè)全新的對(duì)象,在修改它的時(shí)候不去影響到源對(duì)象,那么這個(gè)時(shí)候我們就可能需要深拷貝;反之,淺拷貝就能實(shí)現(xiàn)我們的需求
只是,我們需要注意到一點(diǎn),那就是因?yàn)閷?shí)現(xiàn)深拷貝使用遞歸的方式,就增加了性能的消耗
相信在不斷使用的過(guò)程中,一定會(huì)對(duì)它越來(lái)越熟悉
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/110228.html
摘要:所以,深拷貝是對(duì)對(duì)象以及對(duì)象的所有子對(duì)象進(jìn)行拷貝實(shí)現(xiàn)方式就是遞歸調(diào)用淺拷貝對(duì)于深拷貝的對(duì)象,改變?cè)磳?duì)象不會(huì)對(duì)得到的對(duì)象有影響。 上一篇 JavaScript中的繼承 前言 文章開始之前,讓我們先思考一下這幾個(gè)問(wèn)題: 為什么會(huì)有淺拷貝與深拷貝 什么是淺拷貝與深拷貝 如何實(shí)現(xiàn)淺拷貝與深拷貝 好了,問(wèn)題出來(lái)了,那么下面就讓我們帶著這幾個(gè)問(wèn)題去探究一下吧! 如果文章中有出現(xiàn)紕漏、錯(cuò)誤之處...
摘要:原文地址淺拷貝和深拷貝只針對(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...
摘要:引用數(shù)據(jù)類型是存放在堆內(nèi)存中的,變量實(shí)際上是一個(gè)存放在棧內(nèi)存的指針,這個(gè)指針指向堆內(nèi)存中的地址。棧和堆的區(qū)別其實(shí)淺拷貝和深拷貝的主要區(qū)別就是數(shù)據(jù)在內(nèi)存中的存儲(chǔ)類型不同。這里,對(duì)存在子對(duì)象的對(duì)象進(jìn)行拷貝的時(shí)候,就是深拷貝了。 數(shù)據(jù)類型 在開始拷貝之前,我們從JavaScript的數(shù)據(jù)類型和內(nèi)存存放地址講起。數(shù)據(jù)類型分為基本數(shù)據(jù)類型 和引用數(shù)據(jù)類型 基本數(shù)據(jù)類型主要包括undefin...
摘要:引用類型值引用類型值是保存在堆內(nèi)存中的對(duì)象,變量保存的只是指向該內(nèi)存的地址,在復(fù)制引用類型值的時(shí)候,其實(shí)只復(fù)制了指向該內(nèi)存的地址。 前言 要理解 JavaScript中淺拷貝和深拷貝的區(qū)別,首先要明白JavaScript的數(shù)據(jù)類型。JavaScript有兩種數(shù)據(jù)類型,基礎(chǔ)數(shù)據(jù)類型和引用數(shù)據(jù)類型。js的基本類型:undefined,null,string,boolean,number,s...
摘要:拷貝到,屬性均順利拷貝。大輝小輝,小輝,大輝小輝,小輝,大輝但是,若修改的屬性變?yōu)閷?duì)象或數(shù)組時(shí),那么對(duì)象之間就會(huì)發(fā)生關(guān)聯(lián)。深拷貝不希望對(duì)象之間產(chǎn)生關(guān)聯(lián),那么這時(shí)候可以用到深拷貝。 淺拷貝 之前文章提到,在定義一個(gè)對(duì)象或數(shù)組時(shí),變量存放的往往只是一個(gè)地址。當(dāng)我們對(duì)堆內(nèi)存中的對(duì)象復(fù)制時(shí),如果屬性是對(duì)象或數(shù)組時(shí),這時(shí)候我們拷貝的只是一個(gè)棧內(nèi)存的指針。因此b對(duì)象在訪問(wèn)該屬性時(shí),會(huì)根據(jù)指針尋找...
閱讀 5291·2021-09-22 15:59
閱讀 1872·2021-08-23 09:42
閱讀 2572·2019-08-29 18:42
閱讀 3456·2019-08-29 10:55
閱讀 2070·2019-08-27 10:57
閱讀 1767·2019-08-26 18:27
閱讀 2731·2019-08-23 18:26
閱讀 2928·2019-08-23 14:40