摘要:引用類型值引用類型值是保存在堆內(nèi)存中的對象,變量保存的只是指向該內(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,symbol(es6新增),保存在棧內(nèi)存中
js的引用類型:Object類型, Array類型,Date類型,RegExp類型,F(xiàn)unction類型,基本包裝對象(Boolean類型,Number類型,String類型),單體內(nèi)置對象(Global對象,Math對象),保存在堆內(nèi)存空間中
1.1基本類型值
基本類型值是指在棧內(nèi)存保存的簡單數(shù)據(jù)段,在復(fù)制基本類型值的時(shí)候,會(huì)開辟出一個(gè)新的內(nèi)存空間,將值復(fù)制到新的內(nèi)存空間。
var a = 1; var b = a; a = 2; console.log(a);//輸出2; console.log(b);//輸出1;
var a = 1;
var b = a;
a = 2;
從上面例子看出,當(dāng)一個(gè)變量的值是基本類型,把它復(fù)制給另一個(gè)變量,復(fù)制完成后改變它的值,不會(huì)影響已經(jīng)復(fù)制了它的值的變量。
1.2引用類型值
引用類型值是保存在堆內(nèi)存中的對象,變量保存的只是指向該內(nèi)存的地址,在復(fù)制引用類型值的時(shí)候,其實(shí)只復(fù)制了指向該內(nèi)存的地址。
var a = { name: "Kitty", age: "20", sex: "man" }; var b = a; a.name = "Jack"; console.log(a);//輸出{name: "Jack",age: 20,sex: "man"} console.log(b);//輸出{name: "Jack",age: 20,sex: "man"}
var a = {name: ‘Kitty’,age: ‘20’,sex: ‘man’};
var b = a;
a.name = ‘Jack’;
從上面例子看出,當(dāng)一個(gè)變量的值是引用類型值,把它復(fù)制給另外一個(gè)變量,復(fù)制的只是指向儲(chǔ)存對象內(nèi)存的地址,所以復(fù)制完成后,改變它的值,會(huì)影響復(fù)制了它的值的變量。
注意:如果有兩個(gè)變量的值是引用類型值,就算它們的值完全相同,它們也是不相等的,因?yàn)樗鼈冎赶虻膬?nèi)存地址不同,例子:
當(dāng)一個(gè)變量是對象,如果像上面那樣直接將一個(gè)變量賦值給另一個(gè)變量,如果改變某個(gè)變量的值,另外一個(gè)變量也會(huì)跟著改變,如果我們不想發(fā)生這種情況,就需要寫一個(gè)函數(shù)用來拷貝對象。
深拷貝和淺拷貝的示意圖大致如下:
2.1 對象淺拷貝
var a = {name:"wanger"} var b = Object.assign({}, a) a===b // false b.name = "zhangsan" a.name //"wanger"
上面代碼將原始對象拷貝到一個(gè)空對象,就得到了原始對象的克隆,這時(shí)候a與b指向的是不同的棧對象,所以對b.name重新復(fù)制也不會(huì)影響到a.name。但是如果a.name是一個(gè)對象的引用,而不是一個(gè)字符串,那么上面的代碼也會(huì)遇到一些問題,參考如下代碼:
var a = {name:{firstName:"wang",lastName:"er"}} var b = Object.assign({}, a) a===b // false b.name.firstName = "zhang" a.name.firstName //"zhang"
b.name.firstName又影響到了a.name.firstName,這是因?yàn)镺bject.assign()方法只是淺層拷貝,a.name是一個(gè)棧對象的引用,賦值給b時(shí),b.name也同樣是這個(gè)棧對象的引用,很多時(shí)候,我們不想讓這種事情發(fā)生,所以我們就需要用到對象的深拷貝。
2.2 對象深拷貝
2.2.1 萬能的for循環(huán)實(shí)現(xiàn)對象的深拷貝
var obj = { name: "FungLeo", sex: "man", old: "18" } var obj2 = copyObj(obj) function copyObj(obj) { let res = {} for (var key in obj) { res[key] = obj[key] } return res }
2.2.2 JSON.parse(JSON.stringify(objectToClone))
var obj = { name: "FungLeo", sex: "man", old: "18" } var obj2 = JSON.parse(JSON.stringify(obj))
2.2.3 擴(kuò)展運(yùn)算符實(shí)現(xiàn)對象的深拷貝
var obj = { name: "FungLeo", sex: "man", old: "18" } var { ...obj2 } = obj obj.old = "22" console.log(obj) console.log(obj2)
運(yùn)行結(jié)果如下:
3.1 數(shù)組淺拷貝
var arr = ["old", 1, true, null, undefined]; var new_arr = arr.concat(); // 或者var new_arr = arr.slice()也是一樣的效果; new_arr[0] = "new"; console.log(arr); // ["old", 1, true, null, undefined] console.log(new_arr); // ["new", 1, true, null, undefined]
數(shù)組的淺拷貝,可用concat、slice返回一個(gè)新數(shù)組的特性來實(shí)現(xiàn)拷貝,但是如果數(shù)組嵌套了對象或者數(shù)組的話用concat、slice拷貝只要有修改會(huì)引起新舊數(shù)組都一起改變了,比如:
var arr = [{old: "old"}, ["old"]]; var new_arr = arr.concat(); arr[0].old = "new"; new_arr[1][0] = "new"; console.log(arr); // [{old: "new"}, ["new"]] console.log(new_arr); // [{old: "new"}, ["new"]]
如果數(shù)組元素是基本類型,就會(huì)拷貝一份,互不影響,而如果是對象或者數(shù)組,就會(huì)只拷貝對象和數(shù)組的引用,這樣我們無論在新舊數(shù)組進(jìn)行了修改,兩者都會(huì)發(fā)生變化。這種叫淺拷貝 。
深拷貝就是指完全的拷貝一個(gè)對象,即使嵌套了對象,兩者也相互分離,修改一個(gè)對象的屬性,也不會(huì)影響另一個(gè)。
3.2 數(shù)組深拷貝
3.2.1 利用擴(kuò)展運(yùn)算符...對數(shù)組中嵌套對象進(jìn)行深拷貝
var arr=[{a:1,b:2},{c:1,d:2}]; var arr2=[]; arr.forEach(item=>{ var {...obj}=item; arr2.push(obj); }) arr2[1].d=7 console.log(arr,arr2)
3.2.2 利用lodash庫的cloneDeep方法
var arr=[{a:1,b:2},{c:1,d:2}]; var arr2=_.cloneDeep(arr) arr2[1].d=7; console.log(arr,arr2)
3.2.3 JSON.parse(JSON.stringify(objectToClone))
var arr=[{a:1,b:2},{c:1,d:2}]; var arr2=JSON.parse(JSON.stringify(arr)); arr2[1].d=7; console.log(arr,arr2)
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/108613.html
摘要:在中可以通過添加一個(gè)參數(shù)來實(shí)現(xiàn)遞歸,調(diào)用就可以實(shí)現(xiàn)一個(gè)深拷貝。利用序列化實(shí)現(xiàn)一個(gè)深拷貝 在JavaScript中,對于Object和Array這類引用類型值,當(dāng)從一個(gè)變量向另一個(gè)變量復(fù)制引用類型值時(shí),這個(gè)值的副本其實(shí)是一個(gè)指針,兩個(gè)變量指向同一個(gè)堆對象,改變其中一個(gè)變量,另一個(gè)也會(huì)受到影響。 這種拷貝分為兩種情況:拷貝引用和拷貝實(shí)例,也就是我們說的淺拷貝和深拷貝 淺拷貝(shallow...
摘要:但是進(jìn)行的是淺拷貝,拷貝的是屬性值。對象展開符深拷貝的實(shí)現(xiàn)方式手動(dòng)復(fù)制轉(zhuǎn)成再轉(zhuǎn)回來只有可以轉(zhuǎn)成格式的對象才可以這樣用,像沒辦法轉(zhuǎn)成沒被改到使用方法避免相互引用對象導(dǎo)致死循環(huán),如的情況四參考關(guān)于的淺拷貝和深拷貝 一、理解 淺拷貝只復(fù)制指向某個(gè)對象的指針,而不復(fù)制對象本身,新舊對象還是共享同一塊內(nèi)存。但深拷貝會(huì)另外創(chuàng)造一個(gè)一模一樣的對象,新對象跟原對象不共享內(nèi)存,修改新對象不會(huì)改到原對象。...
摘要:說明外層數(shù)組拷貝的是實(shí)例說明元素拷貝是引用深拷貝在堆中重新分配內(nèi)存,并且把源對象所有屬性都進(jìn)行新建拷貝,拷貝后的對象與原來的對象完全隔離,互不影響。中的方法可以實(shí)現(xiàn)深拷貝,源碼原理也是遞歸使用淺拷貝。 1.淺拷貝 當(dāng)把數(shù)組或?qū)ο蠛唵钨x值給其他變量的時(shí)候,實(shí)際上進(jìn)行的是淺拷貝,淺拷貝是拷貝引用,只是將拷貝后的引用指向同一個(gè)對象實(shí)例,彼此間的操作還會(huì)互相影響。 分為兩種情況:直接拷貝源對象...
摘要:原文地址淺拷貝和深拷貝只針對像這樣的復(fù)雜對象的簡單來說,淺拷貝只拷貝一層對象的屬性,而深拷貝則遞歸拷貝了所有層級。淺拷貝通過來實(shí)現(xiàn)淺拷貝。 原文地址:http://www.silenceboy.com/201... 淺拷貝和深拷貝只針對像Object, Array這樣的復(fù)雜對象的.簡單來說,淺拷貝只拷貝一層對象的屬性,而深拷貝則遞歸拷貝了所有層級。 淺拷貝 通過 Object.ass...
摘要:而大多數(shù)實(shí)際項(xiàng)目中,我們想要的結(jié)果是兩個(gè)變量初始值相同互不影響。所以就要使用到拷貝分為深淺兩種深淺拷貝的區(qū)別淺拷貝只復(fù)制一層對象的屬性,而深拷貝則遞歸復(fù)制了所有層級。 為什么會(huì)用到淺拷貝和深拷貝 首先來看一下如下代碼 let a = b = 2 a = 3 console.log(a) console.log(b) let c = d = [1,2,3] let e = f = {a:...
閱讀 1369·2021-10-19 11:42
閱讀 717·2021-09-22 16:04
閱讀 1867·2021-09-10 11:23
閱讀 1838·2021-07-29 14:48
閱讀 1247·2021-07-26 23:38
閱讀 2812·2019-08-30 15:54
閱讀 1024·2019-08-30 11:25
閱讀 1694·2019-08-29 17:23