# 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); ``` ![](https://i.imgur.com/LcMNb4G.png) 這在這debug時不清楚,當下印出的物件為何 可改成 ``` // 新增css標示更清晰 console.log('%c My Friends','color: orange') console.log({foo, bar, baz}); // 或可以使用 table來印出(注意要放陣列型態進去): console.table([foo, bar, baz]) ``` ![](https://i.imgur.com/pRMf621.png) 2. trace 當不曉得當下方法呼叫的源頭,可使用console.trace()來追蹤 ![](https://i.imgur.com/45EMqSS.png) 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}`); }; ```