JS102 如何輸出和使用模組

前言 :

為了方便日後的維護,我們會將一個 js 檔案中的功能切割成許多 js 的檔案,每個檔案負責不同的功能,假設現在我有個用來處理數字運算的檔案叫做 all.js ,我可以在將這個檔案依功能細切成不同檔案,負責加法運算的就叫 plus.js,負責減法的叫 minus.js,這樣子切檔案的過程就是模組化,我們之後可以根據自己的需求載相對應的模組,如果今天只要用加法運算那載入 plus.js 就好,不用全部 all.js 都載進來,且各功能互相獨立不會被彼此影響,要 debug 也會容易許多。

怎麼做?

已上方的例子為例,我今天想在作業 hw1.js 使用加法功能,那我只要載入 plus.js 就好。
plus.js 輸出 add 這個 function module.exports = add;

1
2
3
4
5
// plus.js
function add(a, b) {
return a + b;
}
module.exports = add;

hw1.js 載入 add 這個 function 來用 const myAdd = require('./plus.js');

1
2
3
// hw1.js
const myAdd = require('./plus.js');
console.log('add', myAdd(4,5)); // add 9

plus.js 也能使用不同的方式輸出,這樣是以物件的方式輸出。

1
2
3
4
5
// plus.js
function add(a, b) {
return a + b;
}
exports.add = add;

所以在 hw1.js 中引用方式也要更改

1
2
3
// hw1.js
const myAdd = require('./plus.js');
console.log('add', myAdd.add(4,5)); // add 9

想使用 plus.js 全部的加法功能要怎麼做?

我們可以將輸入內容寫成物件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// plus.js
function add(a, b) {
return a + b;
}
function threeAdd(a, b, c) {
return a + b + c;
}
module.exports = {
add: add,
threeAdd: threeAdd
};

// 也能這樣寫
// module.exports = {
// add,
// threeAdd
// };

輸入時也能安心使用。

1
2
3
4
5
// hw1.js
const myAdd = require('./plus.js');

console.log('add', myAdd.add(3,4));
console.log('threeAdd', myAdd.threeAdd(3,4,5));

安裝 babel-node ,在 node.js 中使用 ES6 的前置步驟

由於 node.js 還沒有支援 import 的新語法,要使用的話需要再安裝 babel-node 來運行, babel 這個工具會將程式碼中新語法的部分轉成舊的語法,這樣可以確保在大部分的環境下(像是 IE 瀏覽器)都能運行。

這部分想知道更清楚的部分可以去看 Babel 使用簡介與基本使用方法 的章節還有 Babel 的文件,這邊就簡單紀錄流程,如何建立環境。

我們先在本地初始化 npm 用 npm init,接著使用 npm install --save-dev @babel/core @babel/node @babel/preset-env 下載相關套件,接著依 @babel/preset-env 這個套件來設定環境,我們再新增一個 .babelrc 的檔案,加入內容。

1
2
3
4
// .babelrc
{
"presets": ["@babel/preset-env"]
}

這樣我們就能在 node.js 環境中運行 import 或是 ES6 以上的新語法,指令為 npx babel-node 檔案名

使用 ES6 import 語法

我們前面用 requiremodule.exports 載入語法,我們現在來用 import 試試。

plus.js 中輸出改成在想輸出的東西前加入 export 就好。

1
2
3
4
5
6
7
// plus.js
export function add(a, b) {
return a + b;
}
export function threeAdd(a, b, c) {
return a + b + c;
}

或是說統一輸出 export {}

1
2
3
4
5
6
7
8
9
10
11
12
13
// plus.js
function add(a, b) {
return a + b;
}
function threeAdd(a, b, c) {
return a + b + c;
}

export {
add,
threeAdd
}

要注意的是這邊 export 中的東西({}) 不是物件,這樣寫會報錯。

1
2
3
4
export {
add: add,
threeAdd: threeAdd
}

如果想要重新幫功能命名的話請用 as 來做。

1
2
3
4
export {
add as addFunction,
threeAdd as threeAddFunction
}

這裡也記得用新名字 addFunctionthreeAddFunction 載入。

1
2
3
4
5
6
// hw1.js
import {addFunction, threeAddFunction} from './plus.js';

console.log('myAdd', addFunction(3,4));
console.log('myAdd', threeAddFunction(3,4,5));

可以想成這是一份輸出清單,將 addthreeAdd 這類需要輸出的東西放進 {} 清單中,英文是寫說 a list of exported variables

import {addFunction, threeAddFunction} from './plus.js'; 這句意思是說從 plus.js 中載入 addFunctionthreeAddFunction 來用。**{add, threeAdd} 這是解構賦值的寫法。**

想直接載入全部的東西可以用 * as myAdd , * 代表載入 plus.js 內全部 export 的東西,並將這些東西的清單命名為 myAdd

1
2
3
4
5
6
// hw1.js
import * as myAdd from './plus.js';

console.log('myAdd', myAdd.add(3,4));
console.log('myAdd', myAdd.threeAdd(3,4,5));

我對這部分沒什麼概念,一開始 Google 也不知道怎麼下關鍵字,我輸入 export {} not object but block js,這些關鍵字後看到 stackoverflow 的討論後才有些頭緒,雖然討論主題不太一樣,但是在討論串的回答有幫到我。

參考資料:
export mdn
block mdn
Export and Import
Re-exporting modules does not work with object spread

最後一個用法是 export default 這個用法是預設輸出的內容。

1
2
3
4
5
6
7
8
// plus.js
export default function add(a, b) {
return a + b;
}

export function threeAdd(a, b, c) {
return a + b + c;
}

這樣的意思就是預設輸出 add 這個函式。

1
2
3
4
5
6
// hw1.js
import myAdd, {threeAdd} from './plus.js';

console.log('myAdd', myAdd(3,4));
console.log('myAdd', threeAdd(3,4,5));

這樣子 myAdd 就會是預設的 add 函式。