# [JS30] Day.18 Tally String Times with Reduce
###### tags: `JS30`
## 任務 Task
將所有影片的時間加總得出總時間。
==完成時間:10min==
## 步驟 Step
1. 用 `String.split()` 將時間文字轉換成 `array` 分別放入分、秒。
2. 用 `Array.reduce()` 將所有秒數加起來。
3. 轉換成 時、分、秒。
## 筆記 Note
### <font color=#337EA9>JS String.prototype.split</font>
* 語法:`String.split(separator, limit)`
* 將字串分割成 `Array` ,`separator` 為指定分割符號, `limit` 為限制最多回傳 `element` 項目(非必要)。
```javascript=
const fruit = 'apple';
console.log(fruit.split("",3));
//output: ['a','p','p']
```
### <font color=#337EA9>JS Array.prototype.reduce()</font>
* 將一個累加器及每個項目傳入 `callback function`。
* 語法:`Array.reduce(callback(accumulator, currentValue, currentIndex, array), initialValue)`
* `accumulator` :累加器,會將回傳項目不斷的加進去。
* `currentValue` :由左至右的 `element`。
* `currentIndex` :`currentValue` 的 `Index`。
* `initialValue` :累加器最一開始的值,如果沒設則為第一個 `element` 項目,且 `currentIndex` 為 `1`。
## 遇到問題 Problem
:::danger
⚠️ <font color=black>Problem</font>
:::
* 在將時間轉換成秒時,使用 `split` 將時間轉換成 `[min, second]` ,在加總時會發現 `min` 、 `second` 為 String 所以再加一個 `.map(parseFloat)`。
```javascript=
const seconds = timeNodes
.map(node => node.dataset.time)
.map(timeCode => {
const [mins, secs] = timeCode.split(":").map(parseFloat);//轉成小數;
return mins * 60 + secs;
})
console.log(seconds);
//output: (58)[343, 153, 225, 47, 321, 416...]
```
* 問題來了,那如果將 `parseFloat` 換成 <font color=red>`parseInt`</font>呢?
```javascript=4
const [mins, secs] = timeCode.split(":").map(parseInt);
```
* 得到的結果卻是:

* 怎麼會這樣?!把 `min` 跟`second` 拆開來看:
```javascript=4
const [mins, secs] = timeCode.split(":").map(parseInt);
console.log([mins, secs]);
```

* 只有 `secs` 的地方是 `NaN` ,這就奇怪了?照理說應該要馬就是兩個都是 `NaN` 。
* 看一下 `parseInt` 的 MDN:
:::warning
*<font color=black>parseInt(string, radix);
radix : 幾進位,範圍為 2~36。</font>*
:::
* 再看一下 `Array.map()` 的MDN
:::warning
*<font color=black>let new_array = arr.map(function callback( currentValue[, index[, array]]) {
// return element for new_array
}[, thisArg])</font>*
:::
* 因為在使用 `array.map(parseInt)` 是直接呼叫 `parseInt` 所以在預設情況下,每個元素會轉換成:
:::warning
*<font color=black>parseInt(currentValue, index, array);</font>*
:::
* 舉個例子來看:
```javascript=
const a = [1 ,4, 10];
console.log(a.map(parseInt));
//output: [1, NaN, 2]
```
* 將每個項目拆解開來就會是:
```javascript=
parseInt(1, 0, [1, 4, 10]);//0進位預設為10進位,得出1
parseInt(4, 1, [1, 4, 10]);//沒有1進位,得出NaN
parseInt(10, 2, [1, 4, 10]);//10的2進位為2
```
* 那 `float` 沒有這個問題嗎?看一下 MDN
:::warning
*<font color=black>parseFloat(string);
</font>*
:::
* `float` 每有預設的 `radix` 就不會有進位的問題拉!
[參考](https://medium.com/hybrid-maker/%E7%82%BA%E4%BB%80%E9%BA%BC-1-7-11-map-parseint-%E6%9C%83%E5%9B%9E-1-nan-3-6ce698c75de)
:::info
:ok_hand: <font color=black>Revise</font>
:::
* 解決方法:
1. 用 `float` 完美解決。
2. 如果真的想用 `parseInt` ,就把 `callback function` 完整的寫出來就沒問題啦~
```javascript=
const [mins, secs] = timeCode.split(":").map(el => parse(el));
console.log([mins, secs]);
```
