# Intermediate JavaScript
###### tags: `程式導師` `JavaScript` `課程筆記`
## Module 模組
使用已經撰寫好的特定功能程式碼,不需要重新打造輪子。
```javascript
// 到 node.js 查詢可用的模組,再引用到自己的檔案內
var os = require('os')
```
### require/module.exports 與 import/export
將寫好的模組輸出
- `module.exports = <函式名稱>`
- `exports.<自定義名稱> = <函式名稱>`
引入寫好的模組
- `var <自定義名稱> = require('<node 模組名稱>')`
- `var <自定義名稱> = require('./<檔案名稱>')`
```javascript
//將自己寫好的模組輸出,好讓其他檔案引用
//ES5 寫法
function double(n) {
return n * 2
}
module.exports = double // 建議使用這種寫法,可以不同資料型態處理
exports.double = double // 另種寫法,將 export 視為物件
//ES6 寫法
export function double(n) {
return n * 2
}
```
```javascript
//引用他人寫好的模組
var myModule = require('./myModule')
```
### npm/yarn 管理套件
node package manager = npm。
模組或套件的來源,除了自己寫、node.js 套件,還有 npm(類似套件倉庫)。
#### 使用 [npm](https://www.npmjs.com/)
1. 啟用 npm:在專案資料夾內,`npm init`
2. 安裝套件:`npm install <套件名稱>`,專案資料夾內會多一個 node_modules 資料夾,裡面會放套件程式碼。
3. 打包套件:`npm install <套件名稱> --save`,專案資料夾內會多一個 package.json,紀錄專案內使用到的套件。
4. 安裝所有專案內用到的套件:`npm install`。通常在下載他人專案後,要重新 build 才會用到。
:::info
在 npm5 之後,只要 `npm init` 後,以 `npm install` 安裝套件也會自動寫入 package.json 內。
:::
#### npm script
npm script 指的是 package.json 檔案內的 scripts 的腳本。以 `npm run <腳本名稱>` 執行。
例如要執行名為 start 的腳本,就是 `npm run start`,依照下面 package.json 所寫的 start script,會在終端機輸入 `node index.js`,代表直接執行 index.js 檔案。
```json
{
"name": "project",
"version": "1.0.0",
"description": "",
"main": "index.js", //執行主程式
"dependencies": {
"left-pad": "^1.3.0"
},
"scripts": {
"start": "node index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
```
### 使用 [yarn](https://yarnpkg.com/getting-started/usage)
由 Facebook 開發的類似 npm 服務。使用方式也類似 npm,只是速度較快。
1. 安裝專案所有需要的套件:`yarn`
2. 安裝特定套件:`yarn add <套件名稱>`,也會自動更新 package.json
3. 執行 package.json 內的腳本:`yarn run <腳本名稱>`
**比較 npm 與 yarn**
| usage | npm | yarn |
| ----- | --- | ---- |
| start use the package manager | `npm init` | `yarn init` |
| install package | `npm install` | `yarn add` |
| development package | `npm install <套件名稱> --dev` | `yarn add <套件名稱> --dev` |
## Jest 測試
Jest 是現成的程式測試框架。使用前要先[安裝](https://jestjs.io/docs/en/getting-started.html)。
實務開發中,實際執行的程式碼檔案跟測試檔案是分開的。
1. 所以在測試程式碼前,要記得將程式碼 export,讓測試檔案能引用,這樣才能測試。
2. 新增測試檔:index.test.js(慣例命名都是以 .test.js 作為測試檔名的結尾)
3. 將測試檔內容改為要測試的內容
4. 新增 test 到 package.json 的腳本內:`"test": "jest"`
5. 在終端機執行 `npm run test`
:::info
若覺得要更改腳本有點麻煩,想直接執行測試檔案的話,可以用 `npx jest index.test.js`。
npx 是在新版本的 npm 才有。
:::
```javascript
//需測試的程式碼:index.js
function repeat(str, times) {
var result = '';
for (var i=0; i<times; i++) {
result += str
}
return result
}
module.exports = repeat
//測試檔:index.test.js
var repeat = require('./index.js')
test('a 重複 5 次應該要等於 aaaaa',()=>{
expect(repeat("a", 5)).toBe("aaaaa");
});
```
### TDD 測試驅動開發
開發專案的順序是:先寫測試,再寫執行的程式碼。
TDD 開發的優點是能避免「懶得寫測試」的情況,因為必須先寫測試,再根據測試程式碼的結果修改程式碼,當程式碼完成後,測試本來就已完成了。
## ES6
- var → let 與 const,var 的效用範圍是 function 內,cont 跟 let 則是在 block 內,因此會建議使用 let 與 const,避免互相干擾。
- template literals 樣板字串
- destructuring 解構
- spread operator
- rest parameters
- default parameters
- arrow function
### Template Literals 樣板字串
```javascript
let userName = 'Yen';
userName ? console.log(`Hello ${userName}!`):
//原本要用 console.log("Hello" + userName + " !")
```
### Destructuring 解構
```javascript
//解構 array
let arr = [1, 2, 3, 4]
let [first, second, third, fourth] = arr
console.log(first, second) //1 2
//解構 object
let obj = {
name: "Jack",
gender: "male",
address: "taipei",
family : {
father: "Mike"
}
}
//原寫法
let name = obj.name
console.log(name) // Jack
let father = obj.family.father
console.log(father) // Mike
//解構寫法
let {name, gender, address, family:{father}} = obj
console.log(name) // Jack
console.log(father) // Mike
```
### Spread Operator 展開運算子
```javascript
//展開 array
let arr = [1, 2, 3]
let arr2 = [4, 5, 6 ...arr]
console.log(arr2) //[4, 5, 6, 1, 2, 3]
//展開 object
let obj = {
a: 1,
b: 2
}
let obj2 = {
...obj,
c: 3
}
let obj3 = {
...obj,
b: 3
}
console.log(obj2) //{a:1, b:2, c:3}
console.log(obj3) //{a:1, b:3},後面會蓋掉前面的值
```
### Rest Parameters 反向展開
- 將剩下的元素都集合在一起
- ...rest 只能放在最後一項,其後不能再有元素
```javascript
//反向展開 array
let arr = [1, 2, 3]
let arr2 = [1, ...rest]
let [first, ...rest] = arr
console.log(arr2) //[1, 2, 3]
console.log(rest) //[2, 3]
//反向展開 object
let obj = {
a: 1,
b: 2,
c: 3
}
let {a, ...obj2} = obj
console.log(obj2) //{b:2, c:3}
//原寫法
function add (a, b) {
return a + b
}
console.log(add(1, 2))
//反向展開 function
function add(...args) { //args 是陣列,在這題就是 [1, 2]
return args[0] + args[1]
}
console.log(add(1, 2))
```
### Default Parameters 預設值
為沒有輸入值的參數,自動設定一個預設值。
```javascript
function repeat(str, times=5) { //times 的預設值是 5
return str.repeat(times)
}
```
### Arrow Function
```javascript
//舊版
var greeting = function() {
console.log('Hello World!');
};
//新版:ES6 arrow function
const greeting = () => console.log('Hello World');
```