---
# System prepended metadata

title: JavaScript References VS Copying

---

# JavaScript References VS Copying

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

![](https://i.imgur.com/gG6DVBY.jpg)

---

### :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/