---
# System prepended metadata

title: '[JS30] Day.18 Tally String Times with Reduce'
tags: [JS30]

---

# [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);
```

* 得到的結果卻是：

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

* 怎麼會這樣？！把 `min` 跟`second` 拆開來看：
```javascript=4
const [mins, secs] = timeCode.split(":").map(parseInt);
console.log([mins, secs]);
```
![](https://i.imgur.com/yl7JVlw.jpg)

* 只有 `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]);
```
![](https://i.imgur.com/1w8bUUJ.jpg)
