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

資訊專(zhuān)欄INFORMATION COLUMN

JavaScript系列--淺析JavaScript解析賦值、淺拷貝和深拷貝的區(qū)別

laznrbfe / 2014人閱讀

摘要:它將返回目標(biāo)對(duì)象。有些文章說(shuō)是深拷貝,其實(shí)這是不正確的。深拷貝相比于淺拷貝速度較慢并且花銷(xiāo)較大。拷貝前后兩個(gè)對(duì)象互不影響。使用深拷貝的場(chǎng)景完全改變變量之后對(duì)沒(méi)有任何影響,這就是深拷貝的魔力。

一、賦值(Copy)

賦值是將某一數(shù)值或?qū)ο筚x給某個(gè)變量的過(guò)程,分為:

1、基本數(shù)據(jù)類(lèi)型:賦值,賦值之后兩個(gè)變量互不影響

2、引用數(shù)據(jù)類(lèi)型:賦,兩個(gè)變量具有相同的引用,指向同一個(gè)對(duì)象,相互之間有影響

對(duì)基本類(lèi)型進(jìn)行賦值操作,兩個(gè)變量互不影響。

// saucxs
let a = "saucxs";
let b = a;
console.log(b);  // saucxs

a = "change";
console.log(a);   // change

console.log(b);    // saucxs

對(duì)引用類(lèi)型進(jìn)行賦操作,兩個(gè)變量指向同一個(gè)對(duì)象,改變變量 a 之后會(huì)影響變量 b,哪怕改變的只是對(duì)象 a 中的基本類(lèi)型數(shù)據(jù)。

// saucxs
let a = {
    name: "saucxs",
    book: {
        title: "You Don"t Know JS",
        price: "45"
    }
}
let b = a;
console.log(b);
// {
//     name: "saucxs",
//     book: {title: "You Don"t Know JS", price: "45"}
// } 

a.name = "change";
a.book.price = "55";
console.log(a);
// {
//     name: "change",
//     book: {title: "You Don"t Know JS", price: "55"}
// } 

console.log(b);
// {
//     name: "change",
//     book: {title: "You Don"t Know JS", price: "55"}
// }

通常在開(kāi)發(fā)中并不希望改變變量 a 之后會(huì)影響到變量 b,這時(shí)就需要用到淺拷貝和深拷貝。

二、淺拷貝(Shallow Copy) 1、什么是淺拷貝

創(chuàng)建一個(gè)新對(duì)象,這個(gè)對(duì)象有著原始對(duì)象屬性值的一份精確拷貝。如果屬性是基本類(lèi)型,拷貝的就是基本類(lèi)型的值,如果屬性是引用類(lèi)型,拷貝的就是內(nèi)存地址 ,所以如果其中一個(gè)對(duì)象改變了這個(gè)地址,就會(huì)影響到另一個(gè)對(duì)象。

上圖中,SourceObject 是原對(duì)象,其中包含基本類(lèi)型屬性 field1 和引用類(lèi)型屬性 refObj。淺拷貝之后基本類(lèi)型數(shù)據(jù) field2filed1 是不同屬性,互不影響。但引用類(lèi)型 refObj 仍然是同一個(gè),改變之后會(huì)對(duì)另一個(gè)對(duì)象產(chǎn)生影響。

簡(jiǎn)單來(lái)說(shuō)可以理解為淺拷貝只解決了第一層的問(wèn)題,拷貝第一層的基本類(lèi)型值,以及第一層的引用類(lèi)型地址

2、淺拷貝使用場(chǎng)景 2.1 Object.assign()

Object.assign() 方法用于將所有可枚舉屬性的值從一個(gè)或多個(gè)源對(duì)象復(fù)制到目標(biāo)對(duì)象。它將返回目標(biāo)對(duì)象。

有些文章說(shuō)Object.assign() 是深拷貝,其實(shí)這是不正確的。

// saucxs
let a = {
    name: "saucxs",
    book: {
        title: "You Don"t Know JS",
        price: "45"
    }
}
let b = Object.assign({}, a);
console.log(b);
// {
//     name: "saucxs",
//     book: {title: "You Don"t Know JS", price: "45"}
// } 

a.name = "change";
a.book.price = "55";
console.log(a);
// {
//     name: "change",
//     book: {title: "You Don"t Know JS", price: "55"}
// } 

console.log(b);
// {
//     name: "saucxs",
//     book: {title: "You Don"t Know JS", price: "55"}
// }

上面代碼改變對(duì)象 a 之后,對(duì)象 b 的基本屬性保持不變。但是當(dāng)改變對(duì)象 a 中的對(duì)象 book 時(shí),對(duì)象 b 相應(yīng)的位置也發(fā)生了變化。

2.2 展開(kāi)語(yǔ)法 Spread
// saucxs
let a = {
    name: "saucxs",
    book: {
        title: "You Don"t Know JS",
        price: "45"
    }
}
let b = {...a};
console.log(b);
// {
//     name: "saucxs",
//     book: {title: "You Don"t Know JS", price: "45"}
// } 

a.name = "change";
a.book.price = "55";
console.log(a);
// {
//     name: "change",
//     book: {title: "You Don"t Know JS", price: "55"}
// } 

console.log(b);
// {
//     name: "saucxs",
//     book: {title: "You Don"t Know JS", price: "55"}
// }
2.3 Array.prototype.slice方法

slice不會(huì)改變?cè)瓟?shù)組,slice() 方法返回一個(gè)新的數(shù)組對(duì)象,這一對(duì)象是一個(gè)由 beginend(不包括end)決定的原數(shù)組的淺拷貝。

// saucxs
let a = [0, "1", [2, 3]];
let b = a.slice(1);
console.log(b);
// ["1", [2, 3]]

a[1] = "99";
a[2][0] = 4;
console.log(a);
// [0, "99", [4, 3]]

console.log(b);
//  ["1", [4, 3]]

可以看出,改變 a[1] 之后 b[0] 的值并沒(méi)有發(fā)生變化,但改變 a[2][0] 之后,相應(yīng)的 b[1][0] 的值也發(fā)生變化。

說(shuō)明 slice() 方法是淺拷貝,相應(yīng)的還有concat等,在工作中面對(duì)復(fù)雜數(shù)組結(jié)構(gòu)要額外注意。

三、深拷貝(Deep Copy) 3.1 什么是深拷貝?

深拷貝會(huì)拷貝所有的屬性,并拷貝屬性指向的動(dòng)態(tài)分配的內(nèi)存。當(dāng)對(duì)象和它所引用的對(duì)象一起拷貝時(shí)即發(fā)生深拷貝。深拷貝相比于淺拷貝速度較慢并且花銷(xiāo)較大??截惽昂髢蓚€(gè)對(duì)象互不影響。

3.2 使用深拷貝的場(chǎng)景 3.2.1 JSON.parse(JSON.stringify(object))
// saucxs
let a = {
    name: "saucxs",
    book: {
        title: "You Don"t Know JS",
        price: "45"
    }
}
let b = JSON.parse(JSON.stringify(a));
console.log(b);
// {
//     name: "saucxs",
//     book: {title: "You Don"t Know JS", price: "45"}
// } 

a.name = "change";
a.book.price = "55";
console.log(a);
// {
//     name: "change",
//     book: {title: "You Don"t Know JS", price: "55"}
// } 

console.log(b);
// {
//     name: "saucxs",
//     book: {title: "You Don"t Know JS", price: "45"}
// }

完全改變變量 a 之后對(duì) b 沒(méi)有任何影響,這就是深拷貝的魔力。

我們看下對(duì)數(shù)組深拷貝效果如何。

// saucxs
let a = [0, "1", [2, 3]];
let b = JSON.parse(JSON.stringify( a.slice(1) ));
console.log(b);
// ["1", [2, 3]]

a[1] = "99";
a[2][0] = 4;
console.log(a);
// [0, "99", [4, 3]]

console.log(b);
//  ["1", [2, 3]]

對(duì)數(shù)組深拷貝之后,改變?cè)瓟?shù)組不會(huì)影響到拷貝之后的數(shù)組。

但是該方法有以下幾個(gè)問(wèn)題:

(1)會(huì)忽略 undefined

(2)會(huì)忽略 symbol

(3)不能序列化函數(shù)

(4)不能解決循環(huán)引用的對(duì)象

(5)不能正確處理new Date()

(6)不能處理正則

其中(1)(2)(3) undefined、symbol 和函數(shù)這三種情況,會(huì)直接忽略。

// saucxs
let obj = {
    name: "saucxs",
    a: undefined,
    b: Symbol("saucxs"),
    c: function() {}
}
console.log(obj);
// {
//     name: "saucxs", 
//     a: undefined, 
//  b: Symbol(saucxs), 
//  c: ? ()
// }

let b = JSON.parse(JSON.stringify(obj));
console.log(b);
// {name: "saucxs"}

其中(4)循環(huán)引用會(huì)報(bào)錯(cuò)

// saucxs
let obj = {
    a: 1,
    b: {
        c: 2,
           d: 3
    }
}
obj.a = obj.b;
obj.b.c = obj.a;

let b = JSON.parse(JSON.stringify(obj));
// Uncaught TypeError: Converting circular structure to JSON

其中(5)* new Date 情況下,轉(zhuǎn)換結(jié)果不正確。

// saucxs
new Date();
// Mon Dec 24 2018 10:59:14 GMT+0800 (China Standard Time)

JSON.stringify(new Date());
// ""2018-12-24T02:59:25.776Z""

JSON.parse(JSON.stringify(new Date()));
// "2018-12-24T02:59:41.523Z"

解決方法轉(zhuǎn)成字符串或者時(shí)間戳就好了。

// saucxs
let date = (new Date()).valueOf();
// 1545620645915

JSON.stringify(date);
// "1545620673267"

JSON.parse(JSON.stringify(date));
// 1545620658688

其中(6)正則情況下

// saucxs
let obj = {
    name: "saucxs",
    a: /"123"/
}
console.log(obj);
// {name: "saucxs", a: /"123"/}

let b = JSON.parse(JSON.stringify(obj));
console.log(b);
// {name: "saucxs", a: {}}

PS:為什么會(huì)存在這些問(wèn)題可以學(xué)習(xí)一下 JSON。

除了上面介紹的深拷貝方法,

常用的還有jQuery.extend()lodash.cloneDeep(),后面文章會(huì)詳細(xì)介紹源碼實(shí)現(xiàn)。

四、總結(jié)
  和原數(shù)據(jù)是否指向同一對(duì)象     第一層數(shù)據(jù)為基本數(shù)據(jù)類(lèi)型     原數(shù)據(jù)中包含子對(duì)象

賦值 是 改變會(huì)使原數(shù)據(jù)一起改變 改變會(huì)使原數(shù)據(jù)一起改變
淺拷貝 否 改變不會(huì)使原數(shù)據(jù)一起改變 改變會(huì)使原數(shù)據(jù)一起改變
深拷貝 否 改變不會(huì)使原數(shù)據(jù)一起改變 改變不會(huì)使原數(shù)據(jù)一起改變

五、參考

1、深拷貝和淺拷貝

2、MDN之Object.assign()

3、MDN之展開(kāi)語(yǔ)法

4、MDN之Array.stypetype.slice()

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

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

相關(guān)文章

  • 【進(jìn)階4-1期】詳細(xì)解析賦值、拷貝和深拷貝區(qū)別

    摘要:展開(kāi)語(yǔ)法木易楊通過(guò)代碼可以看出實(shí)際效果和是一樣的。木易楊可以看出,改變之后的值并沒(méi)有發(fā)生變化,但改變之后,相應(yīng)的的值也發(fā)生變化。深拷貝使用場(chǎng)景木易楊完全改變變量之后對(duì)沒(méi)有任何影響,這就是深拷貝的魔力。木易楊情況下,轉(zhuǎn)換結(jié)果不正確。 一、賦值(Copy) 賦值是將某一數(shù)值或?qū)ο筚x給某個(gè)變量的過(guò)程,分為下面 2 部分 基本數(shù)據(jù)類(lèi)型:賦值,賦值之后兩個(gè)變量互不影響 引用數(shù)據(jù)類(lèi)型:賦址,兩個(gè)...

    silvertheo 評(píng)論0 收藏0
  • 關(guān)于JavaScript拷貝和深拷貝

    摘要:引用類(lèi)型值引用類(lèi)型值是保存在堆內(nèi)存中的對(duì)象,變量保存的只是指向該內(nèi)存的地址,在復(fù)制引用類(lèi)型值的時(shí)候,其實(shí)只復(fù)制了指向該內(nèi)存的地址。 前言 要理解 JavaScript中淺拷貝和深拷貝的區(qū)別,首先要明白JavaScript的數(shù)據(jù)類(lèi)型。JavaScript有兩種數(shù)據(jù)類(lèi)型,基礎(chǔ)數(shù)據(jù)類(lèi)型和引用數(shù)據(jù)類(lèi)型。js的基本類(lèi)型:undefined,null,string,boolean,number,s...

    shenhualong 評(píng)論0 收藏0
  • JavaScript、深拷貝

    摘要:前言里面淺拷貝和深拷貝是非常關(guān)鍵的知識(shí)點(diǎn),今天就來(lái)通過(guò)本文清楚的了解深淺拷貝以及該如何實(shí)現(xiàn)這兩種拷貝方式。對(duì)象的拷貝又分為淺拷貝和深拷貝。印證了上述所說(shuō)的對(duì)于所有的基本類(lèi)型,簡(jiǎn)單的賦值已經(jīng)是實(shí)現(xiàn)了深拷貝。 前言 JavaScript里面淺拷貝和深拷貝是非常關(guān)鍵的知識(shí)點(diǎn),今天就來(lái)通過(guò)本文清楚的了解深淺拷貝以及該如何實(shí)現(xiàn)這兩種拷貝方式。 深淺拷貝的區(qū)別 拷貝:其實(shí)就是一個(gè)對(duì)象復(fù)制給另外...

    leanxi 評(píng)論0 收藏0
  • JavaScript拷貝和深拷貝區(qū)別和實(shí)現(xiàn)

    摘要:要理解中淺拷貝和深拷貝的區(qū)別,首先要明白的數(shù)據(jù)類(lèi)型有兩種數(shù)據(jù)類(lèi)型,基礎(chǔ)數(shù)據(jù)類(lèi)型和引用數(shù)據(jù)類(lèi)型基礎(chǔ)數(shù)據(jù)類(lèi)型保存在棧內(nèi)存中的簡(jiǎn)單數(shù)據(jù)段,有,,,,引用數(shù)據(jù)類(lèi)型,對(duì)象,保存在堆內(nèi)存空間中存放在棧內(nèi)存中與變量名與內(nèi)存地址存儲(chǔ)在棧內(nèi)存中,與作為對(duì)象存 要理解 JavaScript中淺拷貝和深拷貝的區(qū)別,首先要明白JavaScript的數(shù)據(jù)類(lèi)型 JavaScript有兩種數(shù)據(jù)類(lèi)型,基礎(chǔ)數(shù)據(jù)類(lèi)型和引...

    wenshi11019 評(píng)論0 收藏0
  • JavaScript拷貝和深拷貝

    摘要:但是進(jìn)行的是淺拷貝,拷貝的是屬性值。對(duì)象展開(kāi)符深拷貝的實(shí)現(xiàn)方式手動(dòng)復(fù)制轉(zhuǎn)成再轉(zhuǎn)回來(lái)只有可以轉(zhuǎn)成格式的對(duì)象才可以這樣用,像沒(méi)辦法轉(zhuǎn)成沒(méi)被改到使用方法避免相互引用對(duì)象導(dǎo)致死循環(huán),如的情況四參考關(guān)于的淺拷貝和深拷貝 一、理解 淺拷貝只復(fù)制指向某個(gè)對(duì)象的指針,而不復(fù)制對(duì)象本身,新舊對(duì)象還是共享同一塊內(nèi)存。但深拷貝會(huì)另外創(chuàng)造一個(gè)一模一樣的對(duì)象,新對(duì)象跟原對(duì)象不共享內(nèi)存,修改新對(duì)象不會(huì)改到原對(duì)象。...

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

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

0條評(píng)論

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