# JavaScript Pro Tips 筆記
###### tags: `javascript`
> 原影片網址:
> https://www.youtube.com/watch?v=Mus_vwhTCq0&ab_channel=Fireship
解析影片中所說的一些javascript技巧
## 如何deBug?
1. console.log
```
let foo = { name: 'tom', age:30, firstTime: false };
let bar = { name: 'tom', age:30, firstTime: true };
let baz = { name: 'tom', age:30, firstTime: true };
'Bad Code ❌'
console.log(foo);
console.log(bar);
console.log(foo);
```

這在這debug時不清楚,當下印出的物件為何
可改成
```
// 新增css標示更清晰
console.log('%c My Friends','color: orange')
console.log({foo, bar, baz});
// 或可以使用 table來印出(注意要放陣列型態進去):
console.table([foo, bar, baz])
```

2. trace
當不曉得當下方法呼叫的源頭,可使用console.trace()來追蹤

3. 其他
像是console.time
```
console.time('looper');
let i = 0;
while (i < 100000) {
i++
}
console.timeEnd("looper");
```
console.time() 方法是作為計算器的起始方法。
該方法一般用於測試程序執行的時長。console.timeEnd()方法為計算器的結束方法,並將執行時長顯示在控console上。
## 解構賦值 - destructuring
可以把陣列或物件中的資料解開擷取成為獨立變數。
假設今天有個物件,需要呼叫物件內值來做使用:
```
let turtle = {
name: 'Bob 🐢',
legs: 4,
shell: true,
type: "anphibious",
meal: 10,
diet: "berries"
}
"Bad Code ❌"
function feed(animal) {
return `Feed ${animal.name} ${animal.meal}`
}
```
這會要每次取值時,都要某物件.key,使的程式碼變得長長的
```
"Good Code ⭕"
// 直接在接收物件處,使用解構賦值方式來取,這樣方便許多
function feed({ name, meal, diet }) {
return `Feed ${name} ${meal} kilos of ${diet}`
}
// OR
function feed(animal) {
const { name, meal, diet } = animal;
return `Feed ${name} ${meal} kilos of ${diet}`;
}
```
## 展開運算子(...) - Spread syntax
> 展開運算符是把一個陣列展開成個別的值的速寫語法,它只會在陣列字面定義與函式呼叫時使用
展開運算符(Spread Operator)是把一個陣列展開(expand)成個別值,這個運算符後面必定接著一個陣列。最常見的是用來組合(連接)陣列,對應的陣列方法是concat,以下是一個簡單的範例:
```
const params = [ "hello", true, 7 ]
const other = [ 1, 2, ...params ] // [ 1, 2, "hello", true, 7 ]
```
展開運算符可以作陣列的淺拷貝,當然陣列的淺拷貝有很多種方式,這是新的一種語法,也是目前語法上最簡單的一種:
```
const arr = [1,2,3]
const arr2 = [...arr]
arr2.push(4) //不會影響到arr
```
範例
1. Object
```
const pikachu = { name: 'pikaka'};
const stats = { attack: 50, hp: 80, defense: 45};
'Bad Object Code ❌'
pikachu['hp'] = stats.hp;
pikachu['attack'] = stats.attack;
// OR
const lvl0 = Object.assign(pikachu, stats);
const lvl1 = Object.assign(pikachu, {hp:45});
```
這樣取值方式又臭又長實際上可以使用展開運算子來取值:
```
'Good Object Code ⭕'
const lvl0 = {...pikachu, ...stats};
const lvl0 = {...pikachu, hp:45};
```
2. 陣列使用方式
```
// Arrays
let pokemon = ['Arbok', 'Raichu', 'Sandshrew']
'Bad Array Code ❌'
pokemon.push('Bulbasaur');
pokemon.push('Metapod');
pokemon.push('Weedle');
'Good Array Code ⭕'
// push
let newPoke = [...pokemon,'Bulbasaur', 'Metapod', 'Weedle']; // ["Arbok", "Raichu", "Sandshrew", "Bulbasaur", "Metapod", "Weedle"]
// unshift
let newPoke = ['Bulbasaur', 'Metapod', 'Weedle', ...pokemon];
```
## LOOP
> 作者提到一些關於陣列遍歷上一些語法糖用法,是較為基本的單元
**Bad Loop Code ❌**
```
const orders = [500, 30, 99, 15, 223];
let total = 0;
let withTax = [];
let hightValue = [];
for (let i = 0; i < orders.length; i++) {
// Reduce
total += orders[i];
// Map
withTax.push(orders[i] * 1.1);
// filter
if (orders[i] > 100) {
hightValue.push(orders[i]);
}
}
```
用這傳統方法上會讓程式碼看起來較不乾淨,且可能出現改變到原值的錯誤...等問題,建議使用上能用js以新增的底層方法就用,除非有較為特殊的情形再自行撰寫方法。
**Good Loop ⭕**
```
// Reduce
let total = orders.reduce((acc, cur) => acc + cur);
// Map
let withTax = orders.map(v => v * 1.1);
// filter
let hightValue = orders.filter(v => v > 100);
```
## Async / await
> 非同步請求在撰寫上的小技巧與建議
**bad Promise ❌**
```
let sumRandomAsyncNumss = () => {
let first;
let second;
let third;
return random()
.then((v) => {
first = v;
return random();
})
.then((v) => {
second = v;
return random();
})
.then((v) => {
third = v;
return first + second + third
});
};
```
不斷的.then下去 造成不容易閱讀問題 又臭又長
**Good Promise Code ⭕**
```
let sumRandomAsyncNums = async () => {
const first = await random();
const second = await random();
const third = await random();
console.log(`Result ${first + second + third}`);
};
```