JavaScript之浅复制【拷贝】与深复制【拷贝】【二】
下面了解下什么淺復(fù)制【拷貝】和深復(fù)制【拷貝】,通過下面的閱讀你將了解到:
1、什么是淺復(fù)制以及使用場(chǎng)景 2、什么是深復(fù)制以及使用場(chǎng)景 3、淺復(fù)制和深復(fù)制有哪些方式 復(fù)制代碼一、我們先來了解下,JavaScript基本知識(shí),基本類型和引用類型
基本類型:number、string、boolean、null、undefined 后來es6又增加了一個(gè)基本類型symbol,目前基本類型為6個(gè) 引用類型:Object、 Function、Array 復(fù)制代碼什么是堆【heap】和 棧 【stack】
棧:自動(dòng)分配內(nèi)存,系統(tǒng)自動(dòng)釋放,里面包含值類型和引用類型的地址【引用對(duì)象】
堆:動(dòng)態(tài)分配內(nèi)存,大小不定,系統(tǒng)不會(huì)自動(dòng)釋放,里面存放引用類型的值【實(shí)例對(duì)象】
看個(gè)例子:
let a=1; let b=a; console.log(a)//1 console.log(b)//1 b=3; console.log(b)//3 console.log(a)//1 復(fù)制代碼從例子得出結(jié)論:當(dāng)值賦值給變量時(shí),解析器確定是基本類型值還是引用類型值。基本數(shù)據(jù)類型,是值訪問的,并且可以操作保存在變量中的實(shí)際值。基本類型復(fù)制的時(shí)候,就是在棧中開辟一個(gè)新的存儲(chǔ)區(qū)域用來存儲(chǔ)變量。所以其中一個(gè)值變化,不會(huì)影響另一個(gè)值.
如例子:雖然b=3發(fā)生了改變,但a輸出結(jié)果還是1,印證上面的結(jié)論.
從上面的例子中,可以看出一個(gè)值發(fā)生的改變也影響到了另一個(gè).
如上:obj的name由zjl變?yōu)榱薼isi,這是為什么呢?
引用類型值【實(shí)例對(duì)象】,是存放在堆內(nèi)存中的對(duì)象。與其它語言不同,JavaScript中,不允許直接訪問內(nèi)存位置及不能直接操作內(nèi)存空間。實(shí)際操作的是對(duì)象的引用【指針】,不是實(shí)際的對(duì)象。
補(bǔ)充:對(duì)象引用是棧中的地址,復(fù)制對(duì)象時(shí),相當(dāng)于在棧中開辟新的一塊區(qū)域存放這個(gè)地址(指針),這個(gè)指針指向同一塊堆內(nèi)存位置。所以其中一個(gè)指針對(duì)象發(fā)生改變,另一個(gè)也會(huì)發(fā)生改變。
總結(jié)下區(qū)別,兩者的主要區(qū)別就是,基本類型是值傳遞,引用類型是地址傳遞二、下面就,常見的數(shù)組【Array】和對(duì)象【Object】,來討論下深淺復(fù)制
- 淺復(fù)制:拷貝的是引用對(duì)象--拷貝的是棧中的地址【對(duì)象的引用】,棧中指針指向同一塊堆內(nèi)存【實(shí)例對(duì)象】,因此修改一個(gè)引用對(duì)象,另一個(gè)引用對(duì)象也隨之修改.就像你拿了一把鑰匙打開一扇門,別人拿到你這把鑰匙也能打開這扇門,并且從房間拿走了東西,你拿到這把鑰匙開門后發(fā)現(xiàn)東西少了,簡言之也就是共享了同一個(gè)房間,JavaScript中就是同一塊堆內(nèi)存.
- 深復(fù)制:拷貝的是實(shí)例對(duì)象。因?qū)嵗龑?duì)象放在堆內(nèi)存中的,要想實(shí)現(xiàn)深拷貝,必須重開辟一塊堆內(nèi)存,新創(chuàng)建原對(duì)象的實(shí)例,并保證不同的對(duì)象引用。使原對(duì)象與新建對(duì)象完全隔離互不影響。
1、淺復(fù)制【拷貝】
//數(shù)組淺復(fù)制 let arr=[1,2,3,5,8]; let item=[]; for(let i in arr){item[i]=arr[i]; } item.push(9); console.log('arr==>'+arr);//arr==>1,2,3,5,8 console.log('item==>'+item);//item==>1,2,3,5,8,9 //對(duì)象淺復(fù)制 let obj={name:'zjl',age:'28'}; let list={}; for(let i in obj){list[i]=obj[i]; } list['like']='apple'; console.dir('obj===>'+JSON.stringify(obj)); console.dir('list===>'+JSON.stringify(list));obj===>{"name":"zjl","age":"28"} list===>{"name":"zjl","age":"28","like":"apple"} 復(fù)制代碼以上例子可以看出,數(shù)組、對(duì)象實(shí)現(xiàn)了淺復(fù)制.但是上面的代碼只能實(shí)現(xiàn)一層的拷貝,無法實(shí)現(xiàn)深層的拷貝,如果把上面的代碼改動(dòng)下,如下:
//對(duì)象淺復(fù)制 let obj={name:'zjl',age:'28'}; let list={}; for(let i in obj){list[i]=obj[i]; } list['name']='lisi'; console.dir('obj===>'+JSON.stringify(obj)); console.dir('list===>'+JSON.stringify(list));obj===>{"name":"lisi","age":"28"} list===>{"name":"lisi","age":"28"} 復(fù)制代碼上面的例子,可以看出對(duì)象name被改變了.影響了原始的對(duì)象值.因引用類型為地址傳遞,沒有開辟新的堆內(nèi)存,地址指向同一塊內(nèi)存位置,所以改變一個(gè)對(duì)象另一個(gè)對(duì)象也會(huì)隨之改變。所以無法實(shí)現(xiàn)深層次的復(fù)制【拷貝】.怎樣解決這個(gè)問題,我們需要使用深拷貝【復(fù)制】來完成,繼續(xù)往下看...
2、深復(fù)制【拷貝】: 看下面的例子,遞歸實(shí)現(xiàn)深層復(fù)制:
var china = {nation: '中國',adrress: ['北京', '上海', '廣州'], } //深復(fù)制,要想達(dá)到深復(fù)制就需要用遞歸 function deepCopy(o, c) {var c = c || {}for (var i in o) {if (typeof o[i] === 'object') { //要考慮深復(fù)制問題了if (o[i].constructor === Array) {//這是數(shù)組c[i] = []} else {//這是對(duì)象c[i] = {}}deepCopy(o[i], c[i])} else {c[i] = o[i]}}return c } var result = {} result = deepCopy(china, result); result.nation = '美國'; console.dir(JSON.stringify(result)); //{"adrress":["北京","上海","廣州"],"nation":"美國"} console.dir(JSON.stringify(china)); //{"adrress":["北京","上海","廣州"],"nation":"中國"} 復(fù)制代碼從上面的例子,可以看出已經(jīng)實(shí)現(xiàn)了,真正的復(fù)制.下面看下圖解:
三、深復(fù)制【拷貝】方法還有很多種
深復(fù)制【拷貝】后,兩個(gè)對(duì)象,包括其內(nèi)部的元素互不干擾。
1、JSON.parse(JSON.stringify())反序列化 2、JQuery自帶的,$.extend(true,{},obj); 3、loadsh.js的實(shí)現(xiàn)_.cloneDeep和_.clone(value, true) 復(fù)制代碼感興趣的可以去了解下
鑒于有朋友評(píng)論對(duì)于JSON.parse(JSON.stringify())反序列化存在局限性,現(xiàn)在做以補(bǔ)充: 照舊,還是先看下例子: 1、對(duì)數(shù)組對(duì)象進(jìn)行深層次的拷貝
let obj={ like:'color', list:{item:['green','red'] }}let deepCopy = (JSON.parse(JSON.stringify(obj))); deepCopy.list.item[0]='yellow'; console.log(deepCopy);//{like:'color',list:{item:['yellow','red']} console.log(obj);//{like:'color',list:{item:['green','red']} 復(fù)制代碼2、針對(duì)undefined,function,symbol的拷貝
let obj={x: undefined, y: Object, z: Symbol("")}; console.log('序列化==>'+JSON.stringify(obj)); // 序列化==> '{}' console.log('反序列化==>'+JSON.parse(JSON.stringify(obj))); // 反序列化==> {} // 對(duì)應(yīng)一個(gè)原型 __proto__let arr=[undefined, Object, Symbol("")]; console.log('序列化==>'+JSON.stringify(arr)); // 序列化==> '[null,null,null]' console.log('反序列化 arr==>'+JSON.parse(JSON.stringify(arr))); // 反序列化 arr==> [null,null,null] // 反序列化 對(duì)應(yīng)一個(gè)原型 __proto__復(fù)制代碼從以上實(shí)例得出以下結(jié)論:
undefined、任意的函數(shù)以及symbol值,在序列化過程中會(huì)被忽略(出現(xiàn)在非數(shù)組對(duì)象的屬性值中時(shí))或者被轉(zhuǎn)換成 null(出現(xiàn)在數(shù)組中時(shí)) 復(fù)制代碼JSON.parse(JSON.stringify())雖不能對(duì)undefined,function,symbol進(jìn)行深拷貝,但使用起來簡單,可以滿足大部分的場(chǎng)景,具體還是要根據(jù)需要選擇使用.
JavaScript之閉包【三】
總結(jié)
以上是生活随笔為你收集整理的JavaScript之浅复制【拷贝】与深复制【拷贝】【二】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linu20180415三周第三次课(4
- 下一篇: [Spring Cloud Task]6