javascript
js 浅拷贝直接赋值_浅析JavaScript解析赋值、浅拷贝和深拷贝的区别
一、賦值(Copy)
賦值是將某一數(shù)值或?qū)ο筚x給某個(gè)變量的過(guò)程,分為:
1、基本數(shù)據(jù)類型:賦值,賦值之后兩個(gè)變量互不影響
2、引用數(shù)據(jù)類型:賦**址**,兩個(gè)變量具有相同的引用,指向同一個(gè)對(duì)象,相互之間有影響
對(duì)基本類型進(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ì)引用類型進(jìn)行賦**址**操作,兩個(gè)變量指向同一個(gè)對(duì)象,改變變量?a?之后會(huì)影響變量?b,哪怕改變的只是對(duì)象?a?中的基本類型數(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ì)象屬性值的一份精確拷貝。如果屬性是基本類型,拷貝的就是基本類型的值,如果屬性是引用類型,拷貝的就是內(nèi)存地址?,所以如果其中一個(gè)對(duì)象改變了這個(gè)地址,就會(huì)影響到另一個(gè)對(duì)象。
?
上圖中,`SourceObject`?是原對(duì)象,其中包含基本類型屬性?`field1`?和引用類型屬性?`refObj`。淺拷貝之后基本類型數(shù)據(jù)?`field2`?和?`filed1`?是不同屬性,互不影響。但引用類型?`refObj`?仍然是同一個(gè),改變之后會(huì)對(duì)另一個(gè)對(duì)象產(chǎn)生影響。
簡(jiǎn)單來(lái)說(shuō)可以理解為淺拷貝只解決了第一層的問(wèn)題,拷貝第一層的**基本類型值**,以及第一層的**引用類型地址**。
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è)由?`begin`和?`end`(不包括`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ā)生深拷貝。深拷貝相比于淺拷貝速度較慢并且花銷較大。拷貝前后兩個(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ù)類型
原數(shù)據(jù)中包含子對(duì)象
賦值
是
改變會(huì)使原數(shù)據(jù)一起改變
改變會(huì)使原數(shù)據(jù)一起改變
淺拷貝
否
改變不會(huì)使原數(shù)據(jù)一起改變
改變會(huì)使原數(shù)據(jù)一起改變
深拷貝
否
改變不會(huì)使原數(shù)據(jù)一起改變
改變不會(huì)使原數(shù)據(jù)一起改變
五、參考
總結(jié)
以上是生活随笔為你收集整理的js 浅拷贝直接赋值_浅析JavaScript解析赋值、浅拷贝和深拷贝的区别的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: kswapd0 挖矿_bioset li
- 下一篇: html 表格 左侧表头,左侧是表头的J