国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

淺談深拷貝和淺拷貝

littleGrow / 3110人閱讀

摘要:而引用類型值是指那些保存堆內(nèi)存中的對(duì)象,意思是變量中保存的實(shí)際上只是一個(gè)指針,這個(gè)指針指向內(nèi)存中的另一個(gè)位置,該位置保存對(duì)象。而堆內(nèi)存主要負(fù)責(zé)對(duì)象這種變量類型的存儲(chǔ)。我們需要明確一點(diǎn),深拷貝與淺拷貝的概念只存在于引用類型。

深拷貝和淺拷貝

說(shuō)起深拷貝和淺拷貝,首先我們來(lái)看兩個(gè)栗子

// 栗子1
var a = 1,b=a;
console.log(a);
console.log(b)
b = 2;
console.log(a);
console.log(b)
// 栗子2
var obj1 = {x: 1, y: 2}, obj2 = obj1;
console.log(obj1) //{x: 1, y: 2}
console.log(obj2) //{x: 1, y: 2}
obj2.x = 2; //修改obj2.x
console.log(obj1) //{x: 2, y: 2}
console.log(obj2) //{x: 2, y: 2}

按照慣性思維,栗子1中obj1應(yīng)該跟a一樣,不會(huì)因另外一個(gè)值的改變而改變的啊,而這里卻是obj1跟著obj2的改變而改變了?同樣都是變量,怎么就表現(xiàn)不一樣了呢?難道存在等級(jí)上的優(yōu)劣?此處需要沉思一小會(huì)。要解決這個(gè)問(wèn)題,就要引入一個(gè)JS中基本類型和引用類型的概念了。

基本類型和引用類型
ECMAScript變量包含兩種不同數(shù)據(jù)類型的值:基本類型值和引用類型值。基本類型值指的是那些保存在棧內(nèi)存中的簡(jiǎn)單數(shù)據(jù)段,即這種值完全保存在內(nèi)存中的一個(gè)位置。而引用類型值是指那些保存堆內(nèi)存中的對(duì)象,意思是變量中保存的實(shí)際上只是一個(gè)指針,這個(gè)指針指向內(nèi)存中的另一個(gè)位置,該位置保存對(duì)象。
兩類數(shù)據(jù)的保存方式

從上圖可以看到,棧內(nèi)存主要用于存儲(chǔ)各種基本類型的變量,包括Boolean、Number、String、Undefined、Null等以及對(duì)象變量的指針。而堆內(nèi)存主要負(fù)責(zé)對(duì)象Object這種變量類型的存儲(chǔ)。目前基本類型有:
Boolean、Null、Undefined、Number、String、Symbol,引用類型有:Object、Array、Function。Symbol就是ES6才出來(lái)的,之后也可能會(huì)有新的類型出來(lái)。

讓我們?cè)倩氐角懊娴陌咐踝?中的值為基本類型,栗子2中的值為引用類型,栗子2中的賦值就是典型的淺拷貝。我們需要明確一點(diǎn),深拷貝與淺拷貝的概念只存在于引用類型。

既然已經(jīng)知道了深拷貝與淺拷貝的來(lái)由,那么該如何實(shí)現(xiàn)深拷貝?我們分別來(lái)看看Array和Object自有方法是否支持:

var arr1 = [1, 2];
var arr2 = arr1.slice();
console.log(arr1); //[1, 2]
console.log(arr2); //[1, 2]

arr2[0] = 3; //修改arr2
console.log(arr1); //[1, 2]
console.log(arr2); //[3, 2]

此時(shí),arr2的修改并沒(méi)有影響到arr1,看來(lái)深拷貝的實(shí)現(xiàn)并沒(méi)有那么難嘛。我們把a(bǔ)rr1改成二維數(shù)組再來(lái)看看結(jié)果

var arr1 = [1, 2, [3, 4]];
var arr2 = arr1.slice();
console.log(arr1); //[1, 2, [3, 4]]
console.log(arr2); //[1, 2, [3, 4]]

arr2[2][1] = 5; 
console.log(arr1); //[1, 2, [3, 5]]
console.log(arr2); //[1, 2, [3, 5]]

咦,arr2又改變了arr1,看來(lái)slice()只能實(shí)現(xiàn)一維數(shù)組的深拷貝,并不能實(shí)現(xiàn)真正的深拷貝。與之有同等特性的還有:concat、Array.from() 。

研究完Array,我們來(lái)看看Object

var obj1 = {x: 1, y: 2};
var obj2 = Object.assign({}, obj1);
console.log(obj1) //{x: 1, y: 2}
console.log(obj2) //{x: 1, y: 2}

obj2.x = 2; //修改obj2.x
console.log(obj1) //{x: 1, y: 2}
console.log(obj2) //{x: 2, y: 2}
var obj1 = {
    x: 1, 
    y: {
        m: 1
    }
};
var obj2 = Object.assign({}, obj1);
console.log(obj1) //{x: 1, y: {m: 1}}
console.log(obj2) //{x: 1, y: {m: 1}}
obj2.y.m = 2; //修改obj2.y.m
console.log(obj1) //{x: 1, y: {m: 2}}
console.log(obj2) //{x: 2, y: {m: 2}}

經(jīng)實(shí)踐證明,Object.assign()跟Array一樣也只能實(shí)現(xiàn)一維對(duì)象的深拷貝。造成只能實(shí)現(xiàn)一維對(duì)象深拷貝的原因是第一層的屬性確實(shí)實(shí)現(xiàn)了深拷貝,擁有了獨(dú)立的內(nèi)存,但更深的屬性卻仍然公用了地址,所以才會(huì)造成上面的問(wèn)題。

那怎么真正的實(shí)現(xiàn)引用類型的深拷貝呢?接下來(lái)要有請(qǐng)正主入場(chǎng)

1.JSON.parse(JSON.stringify(obj))

var obj1 = {
    x: 1, 
    y: {
        m: 1
    }
};
var obj2 = JSON.parse(JSON.stringify(obj1));
console.log(obj1) //{x: 1, y: {m: 1}}
console.log(obj2) //{x: 1, y: {m: 1}}

obj2.y.m = 2; //修改obj2.y.m
console.log(obj1) //{x: 1, y: {m: 1}}
console.log(obj2) //{x: 2, y: {m: 2}}

JSON.parse(JSON.stringify(obj)) 簡(jiǎn)單粗暴,簡(jiǎn)簡(jiǎn)單單讓你功力倍增,不過(guò)MDN文檔的描述有句話寫的很清楚:

undefined、任意的函數(shù)以及 symbol 值,在序列化過(guò)程中會(huì)被忽略(出現(xiàn)在非數(shù)組對(duì)象的屬性值中時(shí))或者被轉(zhuǎn)換成 null(出現(xiàn)在數(shù)組中時(shí))。詳情可以戳這里MDN文檔
var obj1 = {
    x: 1,
    y: undefined,
    z: function add(z1, z2) {
        return z1 + z2
    },
    a: Symbol("foo")
};
var obj2 = JSON.parse(JSON.stringify(obj1));
console.log(obj1) //{x: 1, y: undefined, z: ?, a: Symbol(foo)}
console.log(JSON.stringify(obj1)); //{"x":1}
console.log(obj2) //{x: 1}

經(jīng)實(shí)踐證明,在將obj1進(jìn)行JSON.stringify()序列化的過(guò)程中,y、z、a都被忽略了,也就驗(yàn)證了MDN文檔的描述。既然這樣,那JSON.parse(JSON.stringify(obj))的使用也是有局限性的,不能深拷貝含有undefined、function、symbol值的對(duì)象,不過(guò)JSON.parse(JSON.stringify(obj))簡(jiǎn)單粗暴,已經(jīng)滿足90%的使用場(chǎng)景了。
經(jīng)過(guò)驗(yàn)證,我們發(fā)現(xiàn)JS 提供的自有方法并不能徹底解決Array、Object的深拷貝問(wèn)題。只能祭出大殺器:遞歸

2.遞歸

function deepCopy(obj) {
    // 創(chuàng)建一個(gè)新對(duì)象
    let result = {}
    let keys = Object.keys(obj),
        key = null,
        temp = null;

    for (let i = 0; i < keys.length; i++) {
        key = keys[i];    
        temp = obj[key];
        // 如果字段的值也是一個(gè)對(duì)象則遞歸操作
        if (temp && typeof temp === "object") {
            result[key] = deepCopy(temp);
        } else {
        // 否則直接賦值給新對(duì)象
            result[key] = temp;
        }
    }
    return result;
}

var obj1 = {
    x: {
        m: 1
    },
    y: undefined,
    z: function add(z1, z2) {
        return z1 + z2
    },
    a: Symbol("foo")
};

var obj2 = deepCopy(obj1);
obj2.x.m = 2;

console.log(obj1); //{x: {m: 1}, y: undefined, z: ?, a: Symbol(foo)}
console.log(obj2); //{x: {m: 2}, y: undefined, z: ?, a: Symbol(foo)}

可以看到,遞歸完美的解決了前面遺留的所有問(wèn)題。但是,還有一個(gè)非常特殊極端的場(chǎng)景:循環(huán)引用拷貝

var obj1 = {
    x: 1, 
    y: 2
};
obj1.z = obj1;

var obj2 = deepCopy(obj1);

此時(shí)如果調(diào)用剛才的deepCopy函數(shù)的話,會(huì)陷入一個(gè)循環(huán)的遞歸過(guò)程,從而導(dǎo)致爆棧。解決這個(gè)問(wèn)題也非常簡(jiǎn)單,只需要判斷一個(gè)對(duì)象的字段是否引用了這個(gè)對(duì)象或這個(gè)對(duì)象的任意父級(jí)即可

function deepCopy(obj, parent = null) {
    // 創(chuàng)建一個(gè)新對(duì)象
    let result = {};
    let keys = Object.keys(obj),
        key = null,
        temp= null,
        _parent = parent;
    // 該字段有父級(jí)則需要追溯該字段的父級(jí)
    while (_parent) {
        // 如果該字段引用了它的父級(jí)則為循環(huán)引用
        if (_parent.originalParent === obj) {
            // 循環(huán)引用直接返回同級(jí)的新對(duì)象
            return _parent.currentParent;
        }
        _parent = _parent.parent;
    }
    for (let i = 0; i < keys.length; i++) {
        key = keys[i];
        temp= obj[key];
        // 如果字段的值也是一個(gè)對(duì)象
        if (temp && typeof temp=== "object") {
            // 遞歸執(zhí)行深拷貝 將同級(jí)的待拷貝對(duì)象與新對(duì)象傳遞給 parent 方便追溯循環(huán)引用
            result[key] = deepCopy(temp, {
                originalParent: obj,
                currentParent: result,
                parent: parent
            });

        } else {
            result[key] = temp;
        }
    }
    return result;
}

var obj1 = {
    x: 1, 
    y: 2
};
obj1.z = obj1;

var obj2 = deepCopy(obj1);
console.log(obj1); 
console.log(obj2); 
總結(jié)

簡(jiǎn)單的一維層次的拷貝可以利用數(shù)組自身方法和對(duì)象的Object.assign實(shí)現(xiàn),在二維層次上方法失效,無(wú)法實(shí)現(xiàn)深拷貝

簡(jiǎn)單粗暴的常見的拷貝可以通過(guò)JSON.parse(JSON.stringify(obj))實(shí)現(xiàn),但對(duì)于屬性的某些特殊類型的值失效。

終極方法,用遞歸實(shí)現(xiàn)引用類型的深拷貝

當(dāng)然還有其他方法,比如使用第三方庫(kù)內(nèi)封裝的方法

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/102255.html

相關(guān)文章

  • 淺談JavaScript 中深拷貝實(shí)現(xiàn)的方法

    摘要:相信人很多學(xué)習(xí)的過(guò)程中都踩了深拷貝和淺拷貝的坑,深拷貝和淺拷貝的區(qū)別我就不再贅述了,今天我來(lái)寫一下我自己實(shí)現(xiàn)深拷貝的各種方法。中的深拷貝也是用類似方法實(shí)現(xiàn)。 相信人很多學(xué)習(xí)js的過(guò)程中都踩了深拷貝和淺拷貝的坑,深拷貝和淺拷貝的區(qū)別我就不再贅述了,今天我來(lái)寫一下我自己實(shí)現(xiàn)深拷貝的各種方法。 比較簡(jiǎn)單的拷貝方式可以借用瀏覽器的Json對(duì)象去實(shí)現(xiàn),先把對(duì)象轉(zhuǎn)化為json字符串,在解析回對(duì)...

    Vicky 評(píng)論0 收藏0
  • 拷貝和淺拷貝的區(qū)別

    摘要:深拷貝和淺拷貝的區(qū)別背景最近在用框架寫頁(yè)面,賦值給中的對(duì)象時(shí)會(huì)出現(xiàn)一個(gè)問(wèn)題,賦值和被賦值對(duì)象之中任何一個(gè)有變化,另一個(gè)也會(huì)隨之變化。 深拷貝和淺拷貝的區(qū)別 背景:最近在用vue框架寫頁(yè)面,賦值給Vue.$data中的對(duì)象時(shí)會(huì)出現(xiàn)一個(gè)問(wèn)題,賦值和被賦值對(duì)象之中任何一個(gè)有變化,另一個(gè)也會(huì)隨之變化。例如: var b = { foo: 123 }; var vm = new Vue(...

    suemi 評(píng)論0 收藏0
  • js深拷貝和淺拷貝

    摘要:深拷貝和淺拷貝深拷貝和淺拷貝的示意圖大致如下淺拷貝只復(fù)制指向某個(gè)對(duì)象的指針,而不復(fù)制對(duì)象本身,新舊對(duì)象還是共享同一塊內(nèi)存。參考文章什么是深拷貝和淺拷貝及其實(shí)現(xiàn)方式 走在前端的大道上 本篇將自己讀過(guò)的相關(guān)文章中,對(duì)自己有啟發(fā)的章節(jié)片段總結(jié)在這(會(huì)對(duì)原文進(jìn)行刪改),會(huì)不斷豐富提煉總結(jié)更新。 淺拷貝 var m = { a: 10, b: 20 } var n = m; n.a = 15; ...

    MAX_zuo 評(píng)論0 收藏0
  • JS里深拷貝和淺拷貝的釋義

    摘要:本文解釋中深拷貝和淺拷貝的區(qū)別。深拷貝深拷貝指遞歸的復(fù)制對(duì)象的屬性給新對(duì)象。有些時(shí)候一層的深拷貝被認(rèn)為是淺拷貝,比如的值是一個(gè)對(duì)象,淺拷貝出來(lái)的新對(duì)象直接引用了原對(duì)象的對(duì)象,所以也會(huì)相互影響的。 本文解釋javascript中深拷貝和淺拷貝的區(qū)別。 淺拷貝/Shallow Copy 淺拷貝指拷貝了引用值。 var original = {prop1 : Prop1, prop2 : p...

    zollero 評(píng)論0 收藏0
  • 對(duì)深拷貝和淺拷貝的全面理解

    摘要:關(guān)于深拷貝和淺拷貝從原理看淺拷貝拷貝一層,對(duì)象級(jí)別的則拷貝引用深拷貝拷貝多層,每個(gè)層級(jí)的屬性都會(huì)拷貝從現(xiàn)象看復(fù)制了,被修改后,隨變化而變化淺拷貝不變深拷貝深拷貝針對(duì)的復(fù)雜的類型數(shù)據(jù)如直接賦值的單層拷貝,如,雖然不受的影響,但是這也不算做 關(guān)于深拷貝和淺拷貝 從原理看: 淺拷貝:拷貝一層,對(duì)象級(jí)別的則拷貝引用 深拷貝:拷貝多層,每個(gè)層級(jí)的屬性都會(huì)拷貝 從現(xiàn)象看:A復(fù)制了B,B被修改后...

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

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

0條評(píng)論

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