---
# System prepended metadata

title: Intermediate JavaScript
tags: [程式導師, 課程筆記, JavaScript]

---

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

