---
# System prepended metadata

title: 四之 3、 JS 102 ES6
tags: [2020八月第一週, Lidemy心得, JS102, JavaScript續, 進度筆記]

---

# 四之 3、 JS 102 ES6 
###### tags: `JS102` `JavaScript續` `2020八月第一週` `進度筆記` `Lidemy心得` 8/3

---

## 展開運算子 (spread operator)

一般單層陣列:
```
var arr = [1, 2, 3]
var arr2 = [4, 5, 6]

console.log(arr2) 
```

會印出陣列 [4, 5, 6] 。

雙層 array :

```
var arr = [1, 2, 3]
var arr2 = [4, 5, 6, arr]

console.log(arr2) 
```
會印出 [ 4, 5, 6, [ 1, 2, 3] ]

---

如果參了展開運算子:
```
var arr = [1, 2, 3]
var arr2 = [4, 5, 6, ...arr]

console.log(arr2)
```
則會印出 [ 4, 5, 6, 1, 2, 3 ] ， 變成只有一層，可以把這個 array 內的值取出放到其他地方。

---

## spread operator 運用在 function 上

```
function add(a, b, c){
  return a + b + c
}

var arr = [1, 2, 3]
console.log(add(arr))
```
這樣是印不出來的，因為 a 會是 1, 2, 3 ， 而 b 和 c undefined 。

---

這時可以用 spread operator :
```
function add(a, b, c){
  return a + b + c
}

var arr = [1, 2, 3]
console.log(add(...arr))
```

這樣會印出 6 ， 因為把 array 展開了，就是把 `var arr = [ ]` 內的 1, 2, 3 取出放到 ...

----

## obj 也能用 spread operator
```
var obj1 = {
  a: 1,
  b: 2
}

var obj2 = {
  z: 1
}

var obj3 = {
  ...obj1,
  c: 3
}
console.log(obj3)
```
會印出 { a: 1, b: 2, c: 3 } ， 會把原來 obj1 內的屬性 (記得 key/value) ， 拿出來，直接貼到物件內，像是這個樣子:
```
var obj3 = {
  a: 1,
  b: 2,
  c: 3
}
```

---
## 有優先順序
如果宣告 b: 3 ， 會變成 ?
```
var obj1 = {
  a: 1,
  b: 2
}

var obj2 = {
  z: 1
}

var obj3 = {
  ...obj1,
  b: 3
}
console.log(obj3)
```
會印出 { a: 1, b: 3 } ， 會直接改變 b 的值，在後面的會優先。  

如果這樣寫 `b:2` 會蓋掉 `b: 3` :
```
var obj1 = {
  a: 1,
  b: 2
}

var obj2 = {
  z: 1
}

var obj3 = {
  b: 3,
  ...obj1
}
console.log(obj3)
```
後面的值會蓋掉前面的值，印出 { b: 2, a: 1 } 。

---

## 這樣寫的好處 ?

假設有一個 arr = [1, 2, 3] ， 想讓 arr2 跟 arr 的值相同:
```
var arr = [1, 2, 3]
var arr2 = [1, 2, 3]

console.log(arr === arr2)
```
會是 false 兩個是不同陣列。

但用 spread operator 可以讓第二個 array 跟第一個 array 的值相同:

```
var arr = [1, 2, 3]
var arr2 = [...arr]

console.log(arr === arr2)
```
注意，這是 arr2 複製了 arr 的值，但仍是不同陣列 (type)。

---
## 底層記憶體運作

### array 的方面
假設今天我要將一個 nestedArray 插入到另外兩個 array 中:


```
var nestedArray = [4]
var arr = [1, 2, 3, nestedArray]
console.log('arr:', arr)

var arr2 = [...arr] 
// 假如用了 spread operator ， 運作如下面行;
// var arr2 = [1, 2, 3, nestedArray]

console.log('arr2:', arr2)
console.log(arr[3] === arr2[3])
```
會印出:
arr [ 1, 2, 3, [ 4 ] ]
arr2 [ 1, 2, 3, [ 4 ] ]
true

表示其 spread operator 從 arr 取出的值在 arr2 雖然類型不一樣，但都複製了相同的 nestedArray ，兩元素相等， 並指向同一個記憶體位置，去判斷會得到 true 。

---

### obj 的方面:
```
var obj = {
  a: 1,
  b: 2
}

var obj2 = {
  ...obj
}

console.log(obj, obj2, obj === obj2)
```
會印出 { a: 1, b: 2 } { a: 1, b: 2 } false ， 雖然兩物件內值一樣，但是不同類型 (type) ， 記憶體位置不同。
除非 `var obj = obj2` 。


---
參考資料:

[展開運算符與其餘運算符](https://eyesofkids.gitbooks.io/javascript-start-from-es6/content/part4/rest_spread.html)  


[[筆記] JavaScript ES6 中的展開運算子（spread operator）和其餘運算子（rest operator）](https://pjchender.blogspot.com/2017/01/es6-spread-operatorrest-operator.html)  

---

# 四之 4、 JS 102 ES6 其餘參數 (rest parameters) 
###### tags: `JS102` `JavaScript續` `2020八月第一週` `進度筆記` `Lidemy心得` 8/3

反向展開，[其餘參數 (rest parameter)](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Functions/rest_parameters) 可以用於表示不確定數量的值(參數)，並視為陣列。

---

## 反向展開
一般的展開運算子 (spread operator) :  
```
var arr = [1, 2, 3]
var arr2 = [...arr, 4]

console.log(arr2)
```
會印出 [ 1, 2, 3, 4 ] 。

rest parameters 通常也會跟解構一起運用在 spread operator 就像是:
```
var arr = [1, 2, 3, 4]
var [first, ...rest] = arr

console.log(first)
console.log(first, ...rest)
console.log(...rest)
console.log(rest)
```
分別拿到
1
1 2 3 4
2 3 4
[ 2, 3, 4 ]
`...` 展開運算式拿出來的會是值，而純只有 rest parameter 可以直接拿陣列(物件)出來。

## rest parameter 只能放在最後面

rest element must be last element :  
```
var arr = [1, 2, 3, 4]
var [first, ...rest, last] = arr

console.log(rest)
```

`...rest` 只能放在最後面，不能自動配對。

## 也可運用在 obj
```
var obj = {
  a: 1,
  b: 2,
  c: 3
}

var {a, ...obj2} = obj
// var {a, ...rest} = obj;
// rest 可以更名成 obj2 或其他名字;
console.log(obj2)
```
因為 a 被拿開，剩下的參數是 b: 2 和 c: 3 ， 所以只會印出 { b: 2, c: 3 } 。

## 可以展開後又集結回來
```
var obj = {
  a: 1,
  b: 2
}

var obj2 = {
  ...obj, // 展開 a:1, b:2 ;
  c: 3
}

var {a, ...rest} = obj2
/*
因為用 , 把 a 拿開了
var {...rest} = obj2
console.log(rest)
*/

console.log(a, rest)

```
因為用 , 把 a 拿開了，所以會印出 1 { b: 2, c: 3 } ， 只會對 `...` 接上的 rest 起作用，展開或收起來。

## 可以用在函式上
一般函式:
```
function add(a, b) {
  return a + b
}

console.log(add(1, 2))
```
會印出 3。

運用 rest parameter :  

```
function add(...args) {
  console.log(args)
  return args[0] + args[1]
}

console.log(add(1, 2))
```
印出:  
[ 1, 2 ]
3

跟 [arguments](https://hackmd.io/@b9720012/HkM7vGXkD) 很像，但 arguments 是物件，但 ...args 是陣列。
```
function add(a,...args) {
  console.log(args)
  return a + args[0]
}

console.log(add(1, 2))
// console.log(add(1, 2, 3, 4, 5))
// 會得到更多陣列 [2, 3, 4, 5]
```
印出:  
[ 2 ]  
3  
開頭會忽略掉 a 所以得到 [2] ， 而 return a + args[0] 則會相加 1 和第 1 位的 2 ，所以得到 3 。

---
參考資料:

[展開運算子(Spread Operator)與其餘參數(Rest parameters)](http://oldblog.eddychang.me/blog/javascript/45-spread-operator-rest-parameters.html)

[Rest Parameters - 剩餘參數](https://jiepeng.me/2015/12/22/rest-parameters)

---


# 四之 5、 JS 102 ES6 預設參數 (default parameters) 就像是預設值
###### tags: `JS102` `JavaScript續` `2020八月第一週` `進度筆記` `Lidemy心得` 8/4

[預設參數 (default parameters)](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Functions/Default_parameters) 就像是預設值，沒有值進去或是值是未定義的情況，可以已預設值傳入。

---
假設有一個重複 n 次的字串:
```
function repeat(str, times) {
  return str.repeat(times)
}

console.log(repeat('abc', 5))
```

會回傳 abc 並印出 abcabcabcabcabc 。

如果不傳 5 進去:

```
function repeat(str, times) {
  return str.repeat(times)
}

console.log(repeat('abc'))
```
會印出 undefined ， 但 ES6 的新功能，可以在函式內加入新值，例如:
```
function repeat(str, times = 5) {
console.log(times)
  return str.repeat(times)
}

console.log(repeat('abc'))
```
就有會在函式內給 times 一個預設值 5 ， 然後印出 abcabcabcabcabc 。

但如果最末行 repeat 甚麼都不要傳，然後開頭的函式 str 也給個預設值 Hello :  
```
function repeat(str = 'Hello', times = 5) {
// console.log(times)
  return str.repeat(times)
}

console.log(repeat())
```
就會印出 HelloHelloHelloHelloHello 。

## 也可以搭配解構使用預設值
```
function repeat(str = 'Hello', times = 5) {
// console.log(times)
  return str.repeat(times)
}

const obj = {
  a: 1, // 如果沒有 a: 1 就會印出 undefined ;
  b: 2
}

const {a, b} = obj

console.log(a, b)
```
會印出 1 2 。

如果在物件內加上預設值:
```
function repeat(str = 'Hello', times = 5) {
// console.log(times)
  return str.repeat(times)
}

const obj = {
// 如果沒有 a: 1 但最後幫他加入其他數字 ;
  b: 2
}

const {a = 123, b} = obj

console.log(a, b)
```
就會印出 123 2 ， 如果沒有 a: 1 但最後幫他加入其他數字的情況。

如果物件內有 a: 1 但是沒有 b 的情況:
```
function repeat(str = 'Hello', times = 5) {
// console.log(times)
  return str.repeat(times)
}

const obj = {
// 如果沒有 a: 1 但最後幫他加入其他數字 ;
  a: 1
}

const {a = 123, b = 'Hello'} = obj

console.log(a, b)
```
會印出 1 Hello 。

陣列也可以用，跟 array 很像，用途很多，加上預設值就可以少判段很多東西。

---

參考資料:
[Day 07: ES6篇 - Default Parameters(傳入參數預設值)](https://ithelp.ithome.com.tw/articles/10185343)