# JavaScript References VS Copying
#### 從Javascript30-14 學習Javascript中陣列與物件的引用(refrence)及複製(Copying)。
####

---
### :lollipop:Step1
#### 從String、Number、Boolean類型的值開始。
```
let coffee = 100; //先宣告Number型的變量age
let mocha = age; //將此變量賦值給另一個變量age2
console.log(coffee,mocha); // 100 100
coffee = 200;
console.log(coffee,mocha); // 200 100
```
由上例可見對coffee修改並不會對mocha造成影響
### :lollipop:Step2
#### 陣列的複製
```
const players = ['Wes', 'Sarah', 'Ryan', 'Poppy'];
const team = players;
console.log(players, team);
team[3] = 'Lux'; //延續上一個步驟的思路,將值賦予給team[3]
console.log(players, team);
// ["Wes", "Sarah", "Ryan", "Lux"] ["Wes", "Sarah", "Ryan", "Lux"]
```
發現players陣列也被修改了。因為team是這個陣列的引用,並不是複製。team 和 players 這兩個變量指向的是同一個數组。該如何解決問題?接者我們開始進行真正的複製
#### Array.prototype.slice()
slice 得到的结果是一个對原數组的淺拷貝,原數组不會被修改。
```
const team2 = players.slice();
team2[3] = 'Lux2'
console.log(players,team2);
//["Wes","Sarah","Ryan","Lux"]
["Wes","Sarah","Ryan","Lux2"]
```
#### Array.prototype.concat()
使用concat()可以合併陣列:
1. 不會改變原有的數組,而是產生一個新的陣列
2. 可以使用空陣列合併與原本陣列合併
```
const team3 = [].concat(players);
team3[3] = 'Lux3';
console.log(players,team3);
// ["Wes","Sarah","Ryan","Lux"]
["Wes","Sarah","Ryan","Lux4"]
```
#### ES6 擴展語法
```
const team4=[...players];
team4[3] = 'Lux4';
console.log(players,team4);
```
#### Array.from()
使用Array創建新的陣列
```
const team5 = Array.from(players);
team5[3] = 'Lux5';
console.log(players,team5);
```
### :lollipop:Step3
#### 物件的複製
```
const person = {
name: 'Wes Bos',
age: 80
};
```
接著我們思考一下可以如何取得上列物件的複製
```
const captain = person;
captain.number = 99;
console.log(person, captain);
//{name: "Wes Bos", age: 80, number: 99}
//{name: "Wes Bos", age: 80, number: 99}
```
發現person物件的值也被改變了,該如何複製呢?
* [`Object.assign()`](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
使用`Object.assign()`來複製一個或多個物件自身所有可數的屬性到另一個目標物件。
但`Object.assign()`是屬於淺層複製,假設物件裡面還有一個物件的時候還是會修改
到物件的值(如(2))
(1)
```
const cap2 = Object.assign({}, person, { number: 99, age: 12 });
console.log(cap2);
// {name: "Wes Bos", age: 12, number: 99}
```
(2)
```
var school = {
name: 'Geroge',
obj: {
name: 'Jovita'
}
};
var home = Object.assign({}, school);
home.obj.name = 'Anna';
console.log(school.obj.name); // Anna
console.log(home.obj.name); // Anna
```
這樣的話該如何做到深層拷貝呢?
##### JSON轉換
利用JSON先將物件轉換成字串,再將字串格式轉換成物件來實現深層複製。
```
const wes = {
name: 'Wes',
age: 100,
social: {
twitter: '@wesbos',
facebook: 'wesbos.developer'
}
};
const dev = Object.assign({}, wes);
const dev2 = JSON.parse(JSON.stringify(wes));
```
#### 但是使用上述方法有一個問題,若你的物件中含有`undefined` 、 `NaN` 或是 `function` 就無法生成。
```
var b = {
name: 'Geroge',
obj: {
name: 'Jovita'
},
fn: function() { // 消失
console.log('123');
},
un: undefined, // 消失
nan: NaN, 直接變成 null
};
var e = JSON.parse(JSON.stringify(b));
console.log(e);
```
#### 若要解決此問題可以使用框架,如Jquery的`$.extend`就可以做到完全的深層拷貝。
```
var b = {
name: 'George',
obj: {
name: 'Jovita'
},
fn: function() {
console.log('hello');
},
hamburger: undefined,
chips: NaN,
};
var e = $.extend(true, {}, b);
console.log(e);
//{name: 'George', obj: {…}, chips: NaN, fn: ƒ}
```
> 參考資料:
> 1. https://github.com/soyaine/JavaScript30/tree/master/14%20-%20JavaScript%20References%20VS%20Copying
> 2. https://hsiangfeng.github.io/javascript/20200905/1375484447/