###### tags:`JavaScript` `有待補內容` `JS102` `module` `npm` `Unit Tests` `ES6`
# JS102 筆記
## 本章重點
- Modules
- npm/yarn
- Tests(Unit test)
- ES6
***
## Require & Export
### 借別人的東西來用:require
概念:
- 什麼是 module?
- 把內容依用途分成一個個小模組
實作:
- 要怎麼導入模組?
- 在 .js 檔案中用 ·`var 變數名 = require('模組名')`
- 如果是自己寫的,`'模組名'` 會長得像`'./myModule.js'`
- 有些東西可以省略,像是 `.js`
### 把東西借給別人:export
概念:
- 怎麼寫一個 module,讓別人和自己可以用?
- 見實作。
實作:
- 第一種方法:存到一個變數裡,再 export 出去
- 為 module 建立一個 .js 檔案
- 把 module 用 `module.exports = function 名` exports 出去
- 也可以用一個 object 輸出一組 module:
```javascript=
let obj = {
dobule: dobule //已有的function,下同
triple: function(n){
return n * 3;
}
addOne:function(n){
return n + 1;
}
}
module.exports = obj
```
- 第二種方法:直接把 functionName export 出去
```javascript=
exports.double = dobule
exports.triple = function(n) {
return n * 3
}
```
其他說明:
- 一樣建議 module 名稱盡量有語意
### [示範]有了 module 後的優勢
[影片](https://www.lidemy.com/courses/js102-javascript-es6-npm/lectures/6151027)的 12:30 處
- 有了 module 有什麼好處?
- 易管理,需要修改時可以改一個地方就好
- 可重複使用 module
## Node Package Manager, NPM
概念:
- NPM 是什麼?
- a package manager for JavaScript
- 自己寫和 Node.js 提供之外的 module 來源(來自網路)
實作:
- NPM 在下載 Node.js 時通常都已經裝好了
- 怎麼確認?
- 在終端機用 `npm -v` 查看版本號確認是否有下載成功
其他補充:
- package/ module/ library 這三個的意思是差不多的
### npm install:以 left-pad 為例
概念1:
- 如何把 npm 上的 module 裝到我們的資料夾底下?
- 見實作
- npm 把 module 抓下來時到底做了麼?
1. 開一個叫做 node_modules 的資料夾
2. 然後把 install 的 package 存進去
實作1:
- 在終端機用`npm install npm名` 安裝 npm
- 用的時候用`require`導入
```javascript=
var leftPad = require('left-pad');
```
概念2:
- 下載很多 npm 的資料夾很大,我們需要每次都commit 上去嗎?
- 不用, npm 的檔案基本上別人也都下載得到,我們只要讓別人知道用了哪些 npm 他們就可以自己去下載了。
- 怎麼建立?
- 見實作2。
實作2:
- 如何裝 npm 前置
- 用 `npm init` 建立一個叫做 `package.json` 的資料夾
- 裡面的`"dependencies" `物件裡面就我們裝的東西的名稱和版本號
- 怎麼下載 npm
- 開發時使用別人的 npm
- `npm install npm名 --save` //詳見下面 package.json 及下載別人的程式
- 怎麼使用 npm
```javascript=
var leftPad = require('left-pad');
```
- 在 commit 時,大家都怎麼做?
- 通常不會把 npm commit 上去
- 要記得把 npm 所在 folder **的檔名**加到一個命名為 `.gitignore`的文字檔裡面再 commit
- package.json 是什麼?
- 寫著關於這個專案的相關資訊的檔案
- 在下載到有 dependencies (就是有用到其他公開 module)的檔案時, 其他人會參考這裡的資訊去下載檔案。
- 在根目錄中使用`npm init`會自動生成
- 如何把我們用的 library 寫入 json?
- 在 install 別人的 module 時最後面接 `--save`
- (註)npm 5 以後,`--save `已經變成預設的選項了,因此 npm install 不加 `--save` 也一樣會把資訊寫到 package.json 裡面
- 如何把別人 `json`裡有的 npm 下載下來?
- 用`$ npm install`進行
- 忘記 `$ npm install`會怎樣
- 會收到 `can not find module "module name" ` 警告
- 自己有 module 要用 yarn 或 npm 管理時:
- yarn : 用`$ yarn init` 進行
- npm:用`$ npm init` 進行
### npm scripts
概念
- package.json 的 `"script"` 區塊是什麼?
- 在 `script` 可以寫好一些指令
- 可以在終端機下指令來執行這些 `script` 的腳本
實作
- 怎麼在 "scripts" 裡建立指令
- 在 package.json 裡的 "scripts" 裡加入腳本
```json
{ ...
"scripts":
{
"hello": "echo Hello, world",
},
...
}
```
- 怎麼用 npm 執行指令
- 在終端機上用 `npm run 腳本指令` 執行
- 例:
`$ npm run hello`
### yarn :npm 以外的選擇
介紹
- yarn 是什麼?
- 一個和 npm 有著非常相似功用的 manage 工具
- yarn 的特色?
- 是 facebook 開發的一個開放原始碼的東西
- 比 npm 快
- 會自動在 module 被下載時加入 json 的 dependencies list 裡
實作
- 如何安裝
- [Installation | Yarn](https://yarnpkg.com/en/docs/install#mac-stable)
- 指令
|指令|內容|
|:-----:|:-----|
|`$ yarn add "專案名稱"`|等同 `npm install` 但會自己加入 dependencies|
|`$ yarn -v`|查看版本號|
|`$ yarn`|根據 json 下載 dependencies|
|`$ yarn run <scriptName>`|等同 `npm run <scriptName>`|
---
## Unit test
### 為什麼要寫測試?
概念
- 初學者通常怎樣測試 code?
- 用 console.log()
- 想一些 edge case(邊界條件)讓程式跑跑看
- 試著讓測試結果一目了然
```javascript=
function repeat(str, times) {
let result = '';
for(let i = 0; i < times; i += 1) {
result += str;
}
return result;
}
console.log(repeat('a',5) === 'aaaaa')
console.log(repeat('abc',1) === 'abc')
```
- 缺點
- 很難規模化
- 不好執行
### 利用 Jest 來寫你的第一個測試!
概念
- 什麼是 Jest?
- 一套現成的 framwork
- 可以用來幫助進行測試
技術
- 怎麼下載 Jest?
- 照著[官網指示](https://jestjs.io/docs/en/getting-started)用 npm 或者 yarn 下載
- 怎麼寫測試?
- 從原本的 .js 檔裡用`module.exports = functionName` 把 function exports 出來
- 在 `.test.js` 的檔案裡用 require 把檔案引用進來
- 然後照著官網上的寫法針對每一個 unit 寫測試
```javascript =
const stars = require('./hw1');
describe('測試印星星', () => {
test('應該要有一顆星', () => {
expect(stars(1)).toEqual(["*"]);
});
test('應該要有一到三顆星', () => {
expect(stars(3)).toEqual(["*", "**", "***"]);
});
test('應該要有一到六顆星', () => {
expect(stars(6)).toEqual(["*", "**", "***", "****", "*****", "******"]);
});
});
```
- 怎麼樣才可以進行測試?
- 要先有腳本
- 在 package.json 的 `"script"` 裡面寫好腳本
```json
...
"scripts":
{
"hello": "echo Hello, world",
"test":"jest",
...
},
```
- 或者如果只想測試單一檔案:
```json
...
"scripts":
{
"hello": "echo Hello, world",
"test":"jest hw1.test.js",
...
},
```
- 腳本寫好之後,怎麼執行?
- 第一種辦法:用 `$ npm run test`
- 第二種辦法:用 `$ yarn run test`
- 第三種辦法(新版本的 npm 的):`npx jest hw1.test.js`
### 先寫測試再寫程式: Test-driven development,TDD
概念:
- 先寫測試再寫 function 的一種開發流程
- 每改完一次就跑測試,看錯的結果是什麼,再回去改。
- test case 要盡可能詳細,要盡可能把所有的邊界條件都放進來
***
## 配備升級:ES6
概念:
- 什麼是 ECMAScript?
- 一個標準、規範
- Javascript 照著這個規則走
- const 是什麼?
- constant 常數
- 常數不能重新賦值
- let 和 var 的差別
- scoped (作用域)的範圍不同
- let 是以 block 為作用域範圍,var 是以 function 為限
### 再也不需要字串拼接:Template Literals
概念:
- 什麼是字串拼接?
- 把 string 用拼接的方式接起來,就叫做字串拼接
- 有什麼問題?
- 問題一:要印多行字串時,要在字串間加入`\n`才會印多行
- 問題二:如果拼接的字串太多,很容易出現單雙引號混用等語法問題
- Template Literals 怎麼解決這些問題?
- 見實作
實作:
- 如何用 Template Literals 解決多行字串問題?
- 用 ` `` ` 符號
```javascript=
let str = `
Hello,
world.
`
```
- 如何解決多字拼接問題?
- 用類似內嵌的方式把變數鑲嵌進來
```javascript=
function sayHi(name) {
console.log(`Hello my frind ${name}, now is ${new Date()}`);
}
sayHi('nick');
```
- `${}`裡面是可以放程式碼的
- 例如 `${name.toUpperCase}`
### 聽起來很酷的 Destructuring:解構
- 有點複雜,好像是把關鍵字(或者是項)拿出來,就可以直接對應到 object 或 array 中的值
- [MDN](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment)使用說明
- 例子:
```javascript=
const obj = {
father :'papa',
mother :'mama'
}
let {
father
} = obj
console.log(father);
// 'papa'
```
- 另外一種用法:在 function 裡面放大括號,直接輸入物件內的變數
```javascript=
function test({a,b}) {
console.log(a);
}
test({
a:1,
b:2
})
// 1
```
***
### Spread Operator
概念:
- Spread Operator 展開運算子
- syntax:`...`
- 可以展開 object, 包含 array
實作:
```javascript=
let arr = [1, 2, 3];
let arr2 = [4,5,6, ...arr];
console.log(arr2);
// [ 4, 5, 6, 1, 2, 3 ]
```
可以在 object 中展開別人形成新的 obj
```javascript=
let obj = {
a:'1',
b:'2'
}
let result = {
...obj,
c:3
}
console.log(result);
// { a: 1, b: 2, c: 3 }
```
也可以展開物件
```javascript=
let arr = [1, 2, 3];
let result = {
...arr,
c:3
}
// { '0': 1, '1': 2, '2': 3, c: 3 }
```
但是如果有以數字命名的物件性時,物件內的東西會指向最後給他的東西:
```javascript=
let arr = [1, 2, 3];
let obj = {
0:'o',
1:'p'
}
let result = {
...arr,
...obj,
c:3
}
console.log(result);
// { '0': 'o', '1': 'p', '2': 3, c: 3 }
```
- 也可以用來複製一份別的 object 的內容:
```javascript=
let arr = [1, 2, 3]
let arrCopy = [...arr]
console.log(arrCopy)
console.log(arr1 === arrCopy)
// [1, 2, 3]
// false
```
- 如果用 `obj = obj2` 的方式,兩者會指向同一個記憶體位置,此時改變 obj 的值時就會連帶改變 obj2 的值
- 因此如果要複製的是 obj2 的值時 `...`運算子會很好用。
***
### 「反向」的展開:Rest Parameters
概念:(待補)
syntax:`...rest`
***
### 加上預設值:Default Parameters
概念
- 為 function 的 Parameters 設定預設值
實作
```javascript=
function repeat (str = 'hello', times = 2) {
console.log(times);
return str.repeat(times);
}
console.log(repeat());
// 2
// hellohello
```
***
### Function 的更新:箭頭函式 Arrow Function
概念
- 一個宣告 function 的新方法
實作
原本的寫法:
```javascript=
let arr =[1, 2, 3, 4, 5];
console.log(
arr
.filter(function(value) {
return value > 1
})
.map(function(value){
return value * 2
})
)
```
有 arrow function 的寫法:
```javascript=
console.log(
arr
.filter(value => { //把 function 刪掉,然後只有一個參數時,() 也可以省略
return value > 1
})
.map(value => {
return value * 2
})
)
```
更省略的寫法:
```javascript=
console.log(
arr
.filter(value => value > 1) // 整個 () 都不要,直接回傳
.map(value => value * 2)
)
```
### Import 與 Export
概念
- 在 ES6 上面的新的 function import/export 語法
範例
舊寫法:
```javascript=
// export
function add(a,b){
return a + b
}
module.exports = add
// import
let add = require('./utils')
console.log(3,5)
```
新寫法:
```javascript=
// export
export function add(a,b){ // 這裡前面加了 export
return a + b;
}
export const PI = 3.14; // 這裡前面加了 export
// import
import {add, PI} from './utils' // 新語法
console.log(3,5)
```
- 現在的 node 還沒辦法跑 ES6 的 import/export 代碼
- 可以用 `bable-node`指令來跑
其他變形:
```javascript=
// export
function add(a,b){
return a + b;
}
let const PI = 3.14;
export{
add,
PI
}
```
如果想要以其他名稱 export 出去
```javascript=8
export{
add as addFunction,
PI
}
// 記得 import 時也要用這個新名稱才找得到是誰
```
一次全部 import
```javascript=
import * as utils from './utils' // * 就是指所有東西
console.log(utils.addFunction(3,5), utils.PI);
```
總結:
Export 有幾種方式:
export function add(){},使用 import {add} 引入
export { add },與上面那種一樣
`export default function add()`,使用 import add 引入,不需要加大括號
如果想要用其他名字,可以用 as 取別名,例如說 export { add as addFunction }
可以用 import * as utils from 'utils' 把全部都 import 進來
***
## Babel 簡介與基本使用方法
概念
- 什麼是 babel?
- a JavaScript compiler
- [Bable 官網](https://babeljs.io/)
- 為支援度不足的環境,對 code 進行編譯,讓原本不支援的環境也可以跑
- ES6/7/8 => Babel => ES5(或其他更舊的)
- 是一個前端開發的工具
- 前端開發的變化速度比瀏覽器還要快,所以試圖讓彼此相容的工具也很多
實作:
參考[bable](https://www.lidemy.com/courses/402888/lectures/6219705)影片
## 更多 ES6
- 請詳見 [es6-cheatsheet](https://github.com/DrkSephy/es6-cheatsheet)