賦值
賦值是將某一數(shù)值或?qū)ο筚x給某個變量的過程璃谨,分為下面 2 部分
- 基本數(shù)據(jù)類型:賦值沙庐,賦值之后兩個變量互不影響
- 引用數(shù)據(jù)類型:賦址,兩個變量具有相同的引用佳吞,指向同一個對象拱雏,相互之間有影響
對基本類型進(jìn)行賦值操作,兩個變量互不影響底扳。
let a = "muyiy";
let b = a;
console.log(b);
// muyiy
a = "change";
console.log(a);
// change
console.log(b);
// muyiy
為什么要使用淺拷貝和深拷貝
對引用類型進(jìn)行賦址操作铸抑,兩個變量指向同一個對象,改變變量 a 之后會影響變量 b衷模,哪怕改變的只是對象 a 中的基本類型數(shù)據(jù)鹊汛。
let a = {
name: "muyiy",
book: {
title: "You Don't Know JS",
price: "45"
}
}
let b = a;
console.log(b);
// {
// name: "muyiy",
// 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"}
// }
通常在開發(fā)中并不希望改變變量 a 之后會影響到變量 b,這時就需要用到淺拷貝和深拷貝阱冶。
淺拷貝
什么是淺拷貝
創(chuàng)建一個新對象刁憋,這個對象有著原始對象屬性值的一份精確拷貝。如果屬性是基本類型木蹬,拷貝的就是基本類型的值至耻,如果屬性是引用類型,拷貝的就是內(nèi)存地址 镊叁,所以如果其中一個對象改變了這個地址尘颓,就會影響到另一個對象。
上圖中晦譬,SourceObject 是原對象疤苹,其中包含基本類型屬性 field1 和引用類型屬性 refObj。淺拷貝之后基本類型數(shù)據(jù) field2 和 filed1 是不同屬性蛔添,互不影響痰催。但引用類型 refObj 仍然是同一個,改變之后會對另一個對象產(chǎn)生影響迎瞧。
簡單來說可以理解為淺拷貝只解決了第一層的問題夸溶,拷貝第一層的基本類型值,以及第一層的引用類型地址凶硅。
淺拷貝使用場景
1.Object.assign()
Object.assign() 方法用于將所有可枚舉屬性的值從一個或多個源對象復(fù)制到目標(biāo)對象缝裁。它將返回目標(biāo)對象。
let a = {
name: "muyiy",
book: {
title: "You Don't Know JS",
price: "45"
}
}
let b = Object.assign({}, a);
console.log(b);
// {
// name: "muyiy",
// 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: "muyiy",
// book: {title: "You Don't Know JS", price: "55"}
// }
上面代碼改變對象 a 之后,對象 b 的基本屬性保持不變捷绑。但是當(dāng)改變對象 a 中的對象 book 時韩脑,對象 b 相應(yīng)的位置也發(fā)生了變化。
2.Array.prototype.slice()
slice() 方法返回一個新的數(shù)組對象粹污,這一對象是一個由 begin和 end(不包括end)決定的原數(shù)組的淺拷貝段多。原始數(shù)組不會被改變。
// 木易楊
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] 的值并沒有發(fā)生變化进苍,但改變 a[2][0] 之后,相應(yīng)的 b[1][0] 的值也發(fā)生變化鸭叙。說明 slice() 方法是淺拷貝觉啊,相應(yīng)的還有concat等,在工作中面對復(fù)雜數(shù)組結(jié)構(gòu)要額外注意沈贝。
深拷貝
什么是深拷貝
淺拷貝只解決了第一層的問題杠人,如果接下去的值中還有對象的話,那么就又回到剛開始的話題了宋下,兩者享有相同的引用嗡善。要解決這個問題,我們需要引入深拷貝杨凑。深拷貝會拷貝所有的屬性滤奈,并拷貝屬性指向的動態(tài)分配的內(nèi)存。當(dāng)對象和它所引用的對象一起拷貝時即發(fā)生深拷貝撩满。深拷貝相比于淺拷貝速度較慢并且花銷較大蜒程。拷貝前后兩個對象互不影響伺帘。
深拷貝使用場景
1.JSON.parse(JSON.stringify(object))
let a = {
name: "muyiy",
book: {
title: "You Don't Know JS",
price: "45"
}
}
let b = JSON.parse(JSON.stringify(a));
console.log(b);
// {
// name: "muyiy",
// 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: "muyiy",
// book: {title: "You Don't Know JS", price: "45"}
// }
但是該方法有以下幾個問題昭躺。
- 會忽略 undefined
- 會忽略 symbol
- 不能序列化函數(shù)
- 不能解決循環(huán)引用的對象
- 不能正確處理new Date()
- 不能處理正則
let obj = {
name: 'muyiy',
a: undefined,
b: Symbol('muyiy'),
c: function() {}
}
console.log(obj);
// {
// name: "muyiy",
// a: undefined,
// b: Symbol(muyiy),
// c: ? ()
// }
let b = JSON.parse(JSON.stringify(obj));
console.log(b);
// {name: "muyiy"}
- 循環(huán)引用情況下,會報錯
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
- new Date 情況下伪嫁,轉(zhuǎn)換結(jié)果不正確
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)成字符串或者時間戳就好了领炫。
let date = (new Date()).valueOf();
// 1545620645915
JSON.stringify(date);
// "1545620673267"
JSON.parse(JSON.stringify(date));
// 1545620658688
- 正則情況下
let obj = {
name: "muyiy",
a: /'123'/
}
console.log(obj);
// {name: "muyiy", a: /'123'/}
let b = JSON.parse(JSON.stringify(obj));
console.log(b);
// {name: "muyiy", a: {}}