###### tags: `Javascript` `ES6` `模組化` `Yarn` `Jest` `NPM` # JavaScript 102 ─ 重點整理 ## 1. 模組化 將大功能切分成小模組,避免互相影響及方便 Debug。模組有可能為 node.js 內建,或者是自己寫的。 ![](https://i.imgur.com/mWJJ3wc.jpg) ### 如何引用模組(module) 語法:`require()` ```Javascript= let abc = require('os'); ``` os = Operating System(作業系統) ### 查詢作業系統 語法:`.platform()` ```Javascript= let abc = require('os'); console.log(abc.platform()); ``` ### 如何出借模組 首先須先新增一 Js 檔案,將此檔案作為模組的輸出端,輸出你想要輸出的涵式(此為輸出 double 這個涵式) #### 1. 單純輸出 輸出端語法:`module.exports` / `exports.物件鑰匙` ```Javascript= function double(n) { return n * 2 } module.exports = double; ``` ```Javascript= function double(n) { return n * 2 } exports.double = double; ``` 輸入端語法:`require(./檔案名稱)` ```Javascript= let abc = require('./newone'); console.log(abc(3)); #expected answer:6 #因為輸入double這個涵式 ``` mudule.exports 後面等於不僅可以放涵式,也可以放陣列、字串、數值、物件等。放涵式就是輸出涵式、放陣列就是輸出陣列。 #### 2. 將眾多功能結合在物件中 輸出端 ```Javascript= function double(n) { return n * 2 } module.exports = { double: double, triple: function(n) { return n * 3 }, minus: function(n) { return n - 2 } } ``` 輸入端: ```Javascript= let abc = require('./newone'); console.log(abc.double(3), abc.triple(4), abc.minus(5)); //expected answer = 6 12 3 ``` ## 2. NPM(Node Package Manager) 透過此管理別人寫好的套件 ( Package )。 ### 如何使用 [NPM官網](https://www.npmjs.com/),從官網內找到欲使用的功能,將下載指令輸入 cmder,欲使用此功能的檔案務必與下載下來的套件(都放在 node_module 資料夾內)在同一層。這樣才可以順利使用。 #### 下載 left-pad 套件 `npm install left-pad --save` #### `--save`的用意 為了要將此套件寫入 package.json 內。 #### 甚麼是 package.json 此為描述此專案的檔案。裡面會詳細記錄子專案使用的套件、專案建立者、名稱等等。 #### 如何建立 package.json:`npm init` 輸入後看需求輸入使用者名稱、版本...等等。接著使用`ls`確認資料夾內檔案,即會發現一個檔案名稱為 package.json。 如果都將下載的套件都寫入 package.json 的話,就可以將 node_module 資料夾刪掉,再 commit 到 GitHub 上。或是將 node_module 放入 ignore 資料夾內。 #### .json 檔內 scripts 使用說明 ![](https://i.imgur.com/O87Yt2n.jpg) scripts 內可輸入任意快速指令。如圖第一個 key 為 start ,要求為執行 node index.js,所以接下來在 cmder 內輸入`npm run start`,即可執行 node index.js。 #### 常見 scripts 應用 再下載專案下來之後,有些時候需要清除檔案或是新增任何東西時,都可以先進來 .json 檔案內,在 scripts 內新增一個 key,並在元素內新增多個指令,即可在 cmder 內一鍵完成所有指令。 #### 補充說明 .json 檔案內都是物件形式,但內部的 key 較特別的地方在於說需要使用雙引號括起來。 ## 3. Yarn ─ 與 npm相似的另一個套件管理工具 [Yarn 官網](https://yarnpkg.com/en/),由 Facebook 開發而成。 ### 相關語法對照 #### 下載 `npm install` → `yarn` #### 初始化 `npm init` → `yarn init` #### 下載套件 `npm install left-pad --saved` → `yarn add left-pad` #### 快速執行命令 `npm run start` → `yarn run start` ## 4. Jest 測試語法 [Jest](https://jestjs.io/docs/en/getting-started) 是一個協助測試程式資料的套件。 ### 使用說明 大體使用方向與過去模板輸出及輸入使用類似,Jest 有自己的適用語法,以下會進行說明。 一般測試的檔名都是使用 index.test.js。 #### 測試資料語法 一樣在輸出端輸入 `module.exports`,在輸入端輸入`require()`外,外層建議包一個 describe 的函式,並在參數一放入要測試的函式名稱,參數二放入 test 的函式,第一個參數寫這個測試描述,第二個參數放入測試的函示,呈現較為完整的結構。 ```Javascript= let repeat = require('./index.js'); describe ('測試 repeat ', () => { test('a 重複五次應該要等於 aaaaa', function() { expect(repeat('a',5)).toBe('aaaaa'); }); test('p;K 重複三次應該要等於 p;Kp;Kp;K', function() { expect(repeat('p;K',3)).toBe('p;Kp;Kp;K'); }); test('1Q! 重複零次應該要等於 ', function() { expect(repeat('1Q!',0).toBe(' '); });// 盡量多準備這種邊際測資 }); ``` #### 執行測資 ##### 方法一 更新 package.json 將 scripts 去執行 jest。 ```javascript= scripts: { "test": "jest" } ``` 在 cmder 內執行:`npm run test`,即可完成測資。 ##### 方法二 輸入`npx jest + 欲測試檔案名稱` #### Test Driven Development 測試驅動開發 先寫測試後寫涵式 ## 5. ECMAScript 2015 (ES6) 更多 ES6 語法,[詳見此](https://github.com/DrkSephy/es6-cheatsheet)。以下簡單介紹幾個常見的 ES6 語法。 ### 變數宣告方式 #### let 變數只能在作用域當中使用,之後可被更動。 #### const ( constant 常數 ) 宣告一個之後無法被更動的值。 ### 字串拼接 #### 用「``」取代「''」 因為 ES5 語法內在多行拼接的時候需要再加上換行,換成「``」就可以直接進行多行拼接。 #### 用 `${}` 放入欲加入變數 透過大括號可直接加入變數。 ```javascript= function sayHi(name, age) { console.log(`Hi, my name is ${name.toUpperCase()}. I'am ${age} years old. Nice to meet you.`) } sayHi('Nick', 25) /*expected answer: Hi, my name is NICK. I'am 25 years old. Nice to meet you. /* ``` ### 解構 Distructuring 透過解構讓陣列及物件更簡單的被呼叫及執行。更多請看[此](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment)。 #### 陣列 `let [元素名稱1, 元素名稱2, 元素名稱3] = 原本的陣列名稱` ```javascript= let arr = ['apple', 'banana', 'orange']; let [a, b] = arr; console.log(b); //expected answer : banana ``` #### 物件 解構內的物件 key 名稱需與原物件 key 名稱相同。 `let {物件當中的key1, key2} = 物件名稱` ```javascript= let fruitPrice = { apple: 20, banana: 15, orange: 25 }; let {apple, banana, orange} = fruitPrice; console.log(banana); // expected answer : 15 ``` ### 展開 Spread Operator 將陣列或物件當中的元素去除陣列及物件的框架,將元素複製到新的陣列或物件中。更多請看[此](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax)。 #### 使用方式 ##### 陣列 `... + 欲複製的陣列名稱` (可放在陣列中的任一位置) ```javascript= let fruit = ['apple', 'banana', 'orange']; let other = ['pear', 'grape', 'lemon', fruit]; let other1 = ['pear', 'grape', 'lemon', ...fruit]; console.log(other); //expected answer : [ 'pear', 'grape', 'lemon', [ 'apple', 'banana', 'orange' ] ] console.log(other1); //expected answer : [ 'pear', 'grape', 'lemon', 'apple', 'banana', 'orange' ] ``` ##### 物件 `... + 欲複製的物件名稱` (可放在物件中的任一位置) ```javascript= let fruitPrice = {apple: 25, banana: 15, orange: 20 }; let otherFruitPrice = {pear: 30, grape: 35, lemon: 10, fruitPrice }; let otherFruitPrice1 = {pear: 30, ...fruitPrice, grape: 35, lemon: 10 }; console.log(otherFruitPrice); /*expected answer: { pear: 30, grape: 35, lemon: 10, fruitPrice: { apple: 25, banana: 15, orange: 20 } } */ console.log(otherFruitPrice1); /*expected answer: { pear: 30, apple: 25, banana: 15, orange: 20, grape: 35, lemon: 10 } */ ``` #### 記憶體存放位置 因為展開比較像是複製的概念,所以說兩者記憶體內容存放位置不一樣,只是存放內容一樣而已。 而過去的直接將陣列或物件放進來時,這樣就會指向同一個記憶體位置,所以存放位置會一樣。 ##### 陣列 ```javascript= let fruit = ['apple', 'banana', 'orange']; let otherFruit = ['pear', 'grape', 'lemon', fruit]; let otherFruit1 = [...fruit]; console.log(otherFruit[3] === fruit); //answer:true console.log(otherFruit1 === fruit); //answer:false ``` ##### 物件 ```javascript= let otherFruitPrice = {pear: 30, grape: 35, lemon: 10, fruitPrice }; let otherFruitPrice1 = { ...fruitPrice }; console.log(otherFruitPrice.fruitPrice === fruitPrice); //expected answer: true console.log(otherFruitPrice1 === fruitPrice); //expected answer: false ``` ### 反向展開 Rest Parameters 這邊常跟解構共同使用,如果不需要一個一個透過解構定義的話,可以透過 Rest Parameters 將剩餘的元素全放入解構的陣列或物件中。呼叫 Rest Parameters 時也會一次呼叫到所有剩餘被放入的元素。 需特別注意的是,Rest Parameters 只能放在陣列、物件或涵式中的最後一個,不能夾在中間。更多請看[此](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Functions/rest_parameters)。 #### 陣列 此案例中的 Rest Parameters 取名為 other。 ```javascript= let fruit = ['apple', 'banana', 'orange']; let otherFruit = ['lemon','grape', ...fruit]; let [l, ...other] = otherFruit; console.log(otherFruit); //answer:[ 'lemon', 'grape', 'apple', 'banana', 'orange' ] console.log(l); //answer:lemon console.log(other); //answer:[ 'grape', 'apple', 'banana', 'orange' ] ``` #### 物件 此案例中的 Rest Parameters 取名為 rest。 ```javascript= let fruitPrice = { apple: 10, banana: 15, orange: 20 }; let fruitPrice1 = { grape: 50, ...fruitPrice, pear: 25 }; let {grape, ...rest} = fruitPrice1 console.log(fruitPrice1); //answer: { grape: 50, apple: 10, banana: 15, orange: 20, pear: 25 } console.log(grape); //answer: 50 console.log(rest); //answer: { apple: 10, banana: 15, orange: 20, pear: 25 } ``` #### 函式 此案例中的 Rest Parameters 取名為 numbs。 ```javascript= function multiple(a, b, ...numbs) { return a * b * numbs[1] } console.log(multiple(2, 3, 4, 5, 6)); //answer: 2 * 3 * 5 = 30 ``` ### 預設值 Default Parameters 語法:`__=__`(加個等號) 在參數上先加入預設值,如果再使用陣列和物件時沒有放入元素、使用函式時沒有放入引數,那樣電腦就會依照先前所設的預設值跑出結果。更多[詳見此](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters)。 #### 陣列 ```javascript= let fruit = ['apple', 'banana', 'orange']; let [a, b, o, g = 'grape'] = fruit; //g 預設值為'grape' console.log(b); //answer:banana console.log(g); //answer:grape ``` #### 物件 ```javascript= let fruitPrice = { apple: 10, banana: 15, orange: 20 }; let {apple, banana = 20, grape = 40} = fruitPrice // banana 預設值為 20,grape 預設值為 40 console.log(apple); //answer:10 console.log(banana); //answer:15 console.log(grape); //answer:40 ``` #### 函式 ```javascript= function multiple(a, b = 1, c = 5) {  // b 預設值為 1,c 預設值為 5 return a * b * c } console.log(multiple(2, 3)); //answer: 2 * 3 * 5 = 30 ``` ### 箭頭函式 以 => 符號簡化函式的語法,是 Syntax Sugar 的其中之一,在長串語法中可以讓語意的易讀性更高。更多說明詳見[Mozilla](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Functions/Arrow_functions) ```javascript= let arr = [1, 2, 3, 4, 5] console.log( arr .filter(function(value) { return value > 1 }) .map(function(value) { return value * 2 }) ) // 以上是一般的寫法,以下改成箭頭函式 arr .filter((value) => { return value > 1 }) .map((value) => { return value * 2 }) // 當 function 內只有一個參數的時候,括號又可以被省略掉 // function 內直接 return 東西時,大括號可以被省略掉 // 所以可以精簡成以下的兩行 arr .filter(value => value > 1) .map(value => value * 2) ``` 以上的語法上,上下兩種語法呈現的效果相同,但下方的箭頭函式可快速呈現簡易且易讀的語法。但如果說在一個語法內需要包含多個條件及程式時,還是建議寫一般函式。 ### 輸出與輸入 Export and Import #### 輸出端 直接在欲輸出的函式前加入`export`。 ```Javascript= function double(n) { return n * 2 } var PI = 3.1415926 module.exports = { double: double, PI: PI }; ``` 以上是 ES5 的語法,以下是 ES6 的語法,並結合箭頭函式。 ```Javascript= export let double => n * 2 export const PI = 3.1415926 ``` 也可以使用 ```Javascript= let double => n * 2 const PI = 3.1415926 export { double, PI } //在大括弧中可以加上 = 重新命名,例:double = multipleTwo,在輸入端時就可以 multipleTwo 呼叫 ``` #### 輸入端 `import {欲輸出的東西名稱} from '文件名稱'` ```Javascript= var abc = require('./index'); console.log(abc.PI, abc.double(4)); //answer: 3.1415926 8 ``` 以上是 ES5 的語法,以下為 ES6 的語法。 ```Javascript= import {double, PI} from './index'; console.log(double(2), PI); //answer: 4 3.1415926 ``` 除此之外,可以一次將所有語法以 * 引入,並用 as 取名。 ```Javascript= import * as cool from './index'; console.log(cool.double(2), cool.PI); //answer: 4 3.1415926 ``` 或者是 ```Javascript= import {double = multipleTwo, PI} from './index'; console.log(multipleTwo(2), PI); //answer: 4 3.1415926 ``` #### 加入預設值 default 用法 ##### 輸出端 ```Javascript= export const default double => n * 2 //預設輸出就是輸出 double 這個函式 export const PI = 3.1415926 ``` ##### 輸出端 ```Javascript= import double, {PI} from './index'; // 預設值不需要加大括號 console.log(double(2), PI); //answer: 4 3.1415926 ``` ### Babel 安裝與使用 執行以上的 ES6 語法,部分內容需要透過 Babel 才可以順利執行,這邊是[官方](https://babeljs.io/docs/en/next/babel-node.html)的安裝說明,及簡易使用步驟。 #### 簡易步驟 1. 安裝必要套件:npm install --save-dev @babel/core @babel/node @babel/preset-env 2. 新增 .babelrc 檔案 3. 在此檔案填入以下內容(告訴 babel 要用這個 preset): ```Javascript= { "presets": ["@babel/preset-env"] } ``` 4. 在 CMDer 上執行 npx babel-node + 檔案名稱即可執行 ES6 語法。