成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

詳解js深淺復(fù)制

Lin_YT / 3356人閱讀

摘要:從而也引出了所謂的深淺復(fù)制問題。附注對(duì)于淺復(fù)制,其實(shí)還有其他的實(shí)現(xiàn)方式,比如數(shù)組中和方法,對(duì)于這些還是希望大家自己了解,本本主要針對(duì)深淺復(fù)制的實(shí)現(xiàn)原理進(jìn)行解析。

前言

在之前寫繼承的過程談到了深淺復(fù)制的問題,因?yàn)橛凶x者反映到需要解析,趁今天周末寫一篇解析,今天的主體相對(duì)之前來說理解難度低一些,篇幅可能也比較短,諸君按需閱讀即可。

從兩種數(shù)據(jù)類型說起

在js中,變量的類型可以大致分成兩種:基本數(shù)據(jù)類型和引用數(shù)據(jù)類型,其中基本數(shù)據(jù)類型指的是簡單的數(shù)據(jù)段,包括:

Undefined

Null

Boolean

Number

String(字符串在一些其他語言中是被當(dāng)做對(duì)象使用的,屬于引用類型,但在js里是基本類型)

而引用類型的值指的是可能包含多個(gè)值的對(duì)象。可能上面這種描述大家都看過不少,但是有沒有思考過為什么要把數(shù)據(jù)類型這樣分呢?本質(zhì)上,是因?yàn)榛緮?shù)據(jù)類型保存在棧內(nèi)存,而引用類型保存在堆內(nèi)存中。那再進(jìn)一步問:為什么要分兩種保存方式呢? 根本原因在于保存在棧內(nèi)存的必須是大小固定的數(shù)據(jù),引用類型的大小不固定,只能保存在堆內(nèi)存中,但是我們可以把它的地址寫在占內(nèi)存中以供我們?cè)L問。舉個(gè)例子:

var a = 1;//定義了一個(gè)number類型
var obj1 = {//定義了一個(gè)objr類型
    name:"obj"
};

在執(zhí)行這段代碼后,內(nèi)存空間里是這樣的:

因?yàn)檫@種保存方式的存在,所以我們?cè)诓僮髯兞康臅r(shí)候,如果是基本數(shù)據(jù)類型,則按值訪問,操作的就是變量保存的值;如果是引用類型的值,我們只是通過保存在變量中的引用類型的地址類操作實(shí)際對(duì)象。從而也引出了所謂的深淺復(fù)制問題。

深復(fù)制和淺復(fù)制 不同的復(fù)制方式

緊接著上文的內(nèi)容,假設(shè)有以下代碼:

//例子1
var a = 1;
var b = a;//復(fù)制
console.log(b)//1
a = 2;//改變a的值
console.log(b)//1

可以看到,我們復(fù)制完b以后,即使改變a的值,b也不會(huì)改變,因?yàn)閍和b是相互獨(dú)立的,按照上面的圖,也就是在棧內(nèi)存中創(chuàng)建了一個(gè)變量b 保存的值也是2;

//例子2
var color1 = ["red","green"];
var color2 = color1;//復(fù)制
console.log(color2)//["red","green"];
color1.push("black") ;//改變color1的值
console.log(color2)//["red","green","black"]

在例子2中,我們按照完全相同的步驟,操作了一個(gè)數(shù)組,但是返回的結(jié)果卻完全不一樣,因?yàn)榇藭r(shí)的復(fù)制,實(shí)際上是這樣:

我們只是復(fù)制了一次引用類型的地址而已,所以,不管接下來我們是操作color1還是color2,本質(zhì)上都是操作同一個(gè)數(shù)組對(duì)象。

深復(fù)制和淺復(fù)制

剛剛說到,簡單的賦值沒有辦法復(fù)制引用類型,那如果我們就是想復(fù)制上面的color1數(shù)組怎么辦呢?可以這樣:

var color1 = ["red","green"]; 
var color2 = [];
//復(fù)制
for(var i  = 0;i < color1.length;i++){
    color2[i] = color1[i]; 
}
console.log(color2)//["red","green"];
color1.push("black") ;//改變color1的值
console.log(color2)//["red","green"]

這一次我們先創(chuàng)建了一個(gè)空數(shù)組color2,然后讓color2的每個(gè)值都和color1對(duì)應(yīng)相等,最后的color1color2是相互獨(dú)立的了,滿足了我們的需要。當(dāng)然對(duì)于對(duì)象類型也是一樣的,使用for-in遍歷取代這里的for循環(huán)即可。

問題真的就這樣解決了嗎?當(dāng)然沒有,不過以上這種只復(fù)制了第一層屬性的方式就叫做淺復(fù)制,淺復(fù)制有什么缺陷呢?我們可以先思考一下,從直接使用=符號(hào)賦值進(jìn)行復(fù)制到淺復(fù)制,能夠復(fù)制成功(成功是指復(fù)制的結(jié)果與復(fù)制源完全獨(dú)立),是因?yàn)槲覀儚?fù)制的對(duì)象都是基本類型,怎么解釋呢?

在復(fù)制基本數(shù)據(jù)類型時(shí),我們直接使用=完成復(fù)制

在引用類型的時(shí)候,我們循環(huán)遍歷對(duì)象,對(duì)每個(gè)屬性或值使用=完成復(fù)制

有沒有注意到上文的color1例子使用淺復(fù)制之所以能夠復(fù)制成功,是因?yàn)?strong>數(shù)組中的每一項(xiàng)都是基本數(shù)據(jù)類型(string),所以猜出了淺復(fù)制的局限了嗎?假如數(shù)組中某一項(xiàng)保存的是一個(gè)對(duì)象,或者是一個(gè)數(shù)組,又或者對(duì)象的某個(gè)屬性還是一個(gè)對(duì)象呢?(換句話說就是引用類型的某個(gè)屬性還是引用類型),如:

var person = {
    name:"lin",
    score:{
        physics:85,
        math:99
    }
}

這個(gè)對(duì)象的分?jǐn)?shù)score屬性就還是一個(gè)對(duì)象,那我們使用前面提到for-in遍歷復(fù)制的時(shí)候,對(duì)score的復(fù)制,不就又變成了我們前面提到的只復(fù)制了地址的情況嗎?再想想淺復(fù)制實(shí)現(xiàn)的原理,相信大家猜到了深復(fù)制實(shí)現(xiàn)的方式:對(duì)屬性中所有引用類型的值,遍歷到是基本類型的值為止,從這種方式上,我們很容易就可以想到利用遞歸來實(shí)現(xiàn)深復(fù)制。

function deepCopy (obj) {
    var result;

    //引用類型分?jǐn)?shù)組和對(duì)象分別遞歸
    if (Object.prototype.toString.call(obj) == "[object Array]") {
      result = []
      for (i = 0; i < obj.length; i++) {
        result[i] = deepCopy(obj[i])
      }
    } else if (Object.prototype.toString.call(obj) == "[object Object]") {
      result = {}
      for (var attr in obj) {
        result[attr] = deepCopy(obj[attr])
      }
    }
    //值類型直接返回
    else {
      return obj
    }
    return result
}

上面的函數(shù)很簡單:對(duì)于傳入的參數(shù),首先判斷是否為引用類型,如果不是,直接返回即可;如果是,循環(huán)遍歷該對(duì)象的屬性,如果某個(gè)屬性還是引用類型,則針對(duì)該屬性再次調(diào)用deepCopy函數(shù),從而完成深復(fù)制。

附注

對(duì)于淺復(fù)制,其實(shí)還有其他的實(shí)現(xiàn)方式,比如數(shù)組中concatslice方法,對(duì)于這些還是希望大家自己了解,本本主要針對(duì)深淺復(fù)制的實(shí)現(xiàn)原理進(jìn)行解析。

小結(jié)

對(duì)于深淺復(fù)制的區(qū)別,其實(shí)核心的關(guān)鍵點(diǎn)就是是只復(fù)制了第一屬性還是完全復(fù)制了所有的屬性,可能有些地方寫的稍顯啰嗦或者描述不當(dāng),歡迎提出意見和建議(然而我并不一定會(huì)聽,哈哈)。如果對(duì)讀者有幫助,還是希望能點(diǎn)個(gè)推薦。以上內(nèi)容屬于個(gè)人見解,如果有不同意見,歡迎指出和探討。請(qǐng)尊重作者的版權(quán),轉(zhuǎn)載請(qǐng)注明出處,如作商用,請(qǐng)與作者聯(lián)系,感謝!

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/82197.html

相關(guān)文章

  • 詳解js深淺復(fù)制問題

    摘要:二這么分的好處就是在于節(jié)省內(nèi)存資源,便于合理回收內(nèi)存詳解中的深淺復(fù)制有了上面的鋪墊,那么我們理解起深淺復(fù)制就變得容易的許多。 前言 對(duì)于前端開發(fā)來說,我們經(jīng)常能夠遇到的問題就是js的深淺復(fù)制問題,通常情況下我們解決這個(gè)問題的方法就是用JSON.parse(JSON.Stringify(xx))轉(zhuǎn)換或者用類似于Inmmutable這種第三方庫來進(jìn)行深復(fù)制,但是我們還是要弄懂其中原理,這樣...

    X1nFLY 評(píng)論0 收藏0
  • 前端進(jìn)擊的巨人(二):棧、堆、隊(duì)列、內(nèi)存空間

    摘要:中有三種數(shù)據(jù)結(jié)構(gòu)棧堆隊(duì)列。前端進(jìn)擊的巨人一執(zhí)行上下文與執(zhí)行棧,變量對(duì)象中解釋執(zhí)行棧時(shí),舉了一個(gè)乒乓球盒子的例子,來演示棧的存取方式,這里再舉個(gè)栗子搭積木。對(duì)于基本類型,棧中存儲(chǔ)的就是它自身的值,所以新內(nèi)存空間存儲(chǔ)的也是一個(gè)值。 面試經(jīng)常遇到的深淺拷貝,事件輪詢,函數(shù)調(diào)用棧,閉包等容易出錯(cuò)的題目,究其原因,都是跟JavaScript基礎(chǔ)知識(shí)不牢固有關(guān),下層地基沒打好,上層就是豆腐渣工程,...

    edgardeng 評(píng)論0 收藏0
  • JS專題之深淺拷貝

    摘要:在之前的文章專題之?dāng)?shù)據(jù)類型和類型檢測中我有講過,中的數(shù)據(jù)類型分為兩種,基本數(shù)據(jù)類型和引用數(shù)據(jù)類型,基本數(shù)據(jù)類型是保存在棧的數(shù)據(jù)結(jié)構(gòu)中的是按值訪問,所以不存在深淺拷貝問題。 前言 在開發(fā)過程中,偶爾會(huì)遇到這種場景,拿到一個(gè)數(shù)據(jù)后,你打算對(duì)它進(jìn)行處理,但是你又希望拷貝一份副本出來,方便數(shù)據(jù)對(duì)比和以后恢復(fù)數(shù)據(jù)。 那么這就涉及到了 JS 中對(duì)數(shù)據(jù)的深淺拷貝問題,所謂深淺拷貝,淺拷貝的意思就是,...

    ASCH 評(píng)論0 收藏0
  • 深入理解JS深淺拷貝

    摘要:深拷貝相比于淺拷貝速度較慢并且花銷較大。所以在賦值完成后,在棧內(nèi)存就有兩個(gè)指針指向堆內(nèi)存同一個(gè)數(shù)據(jù)。結(jié)果如下擴(kuò)展運(yùn)算符只能對(duì)一層進(jìn)行深拷貝如果拷貝的層數(shù)超過了一層的話,那么就會(huì)進(jìn)行淺拷貝那么我們可以看到和展開原算符對(duì)于深淺拷貝的結(jié)果是一樣。 JS中數(shù)據(jù)類型 基本數(shù)據(jù)類型: undefined、null、Boolean、Number、String和Symbol(ES6) 引用數(shù)據(jù)類型:...

    JackJiang 評(píng)論0 收藏0
  • js深淺復(fù)制

    摘要:總結(jié)綜上所述,數(shù)組的深拷貝比較簡單,方法沒有什么爭議,對(duì)象的深拷貝,比較好的方法是用的方法實(shí)現(xiàn),或者遞歸實(shí)現(xiàn),比較簡單的深復(fù)制可以使用實(shí)現(xiàn)參考資料知乎中的深拷貝和淺拷貝深入剖析的深復(fù)制 深淺復(fù)制對(duì)比 因?yàn)镴avaScript存儲(chǔ)對(duì)象都是存地址的,所以淺復(fù)制會(huì)導(dǎo)致 obj 和obj1 指向同一塊內(nèi)存地址。我的理解是,這有點(diǎn)類似數(shù)據(jù)雙向綁定,改變了其中一方的內(nèi)容,都是在原來的內(nèi)存基礎(chǔ)上做...

    Apollo 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

Lin_YT

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<