剛開始寫js的時候,寫的都是奈米級單元的小東西,完全沒感覺需要模組化什麼東西,但前輩題點說,雖然現在的東西還簡單,實際上應該沒有模組化的必要,但若能在這樣的狀態下練習,可以先有一些概念,未來面對複雜專案,會比較無痛上手。
那時候有個疑問,拆模組和把相同的code抓出來寫成一個function有什麼不一樣呢?初步看起來都是為了增加複用性並好管理對吧?這樣的想法大概只有抓到模組化粗淺的皮毛,除了能跨檔案規模的複用之外,其實還有其他的好處。
參考Jonas課程中提到的,如果把模組化的過程類比成組裝電腦,我們會有不同的部件執行各樣的功能,像是CPU負責運算,電源供應器提供系統運作的電力,顯卡處理圖像數據並在螢幕上繪製影像等等,把這些小單元組合起來,就可以一個執行更大的任務。如此一來,可以想像會有下面的好處:
應用
,會大大提昇工作的品質。一開始js其實沒有模組化的功能,但世界各地的天才們紛紛想出各種方法來實現模組化,各種像是AMD, Common js等等的技術,後續ES6之後,js官方也有了自己的模組管理系統ES module。
我自己是從ES module開始的,雖然還是有大量的第三方套件是用cjs,也能想像未來會有一段過渡期,但相信未來會逐漸以ES module為主。
ES module使用import
和export
作為匯入匯出的關鍵字。export的方式有兩種,相對應的import方式也有一點點不一樣。
export default function (input) {
if (input !== 0) {
return "電影照常播放";
} else {
return "今天電影沒播喔..";
}
}
當匯入時,可任意指定函式名稱像是checkPlaying
,作為後續呼叫的名字:
import checkPlaying from "./moviePlay.js";
console.log(checkPlaying(0)); //今天電影沒播喔..
console.log(checkPlaying(100)); // 電影照常播放
export const isEmptyStr = function (input) {
if (input.trim().length === 0)
throw new Error("你沒有輸入東西喔..請重新輸入");
return input;
};
export const isNagtive = function (input) {
if (+input < 0) throw new Error("這是一個負數,請重新輸入");
return input;
};
const includeSpecialChart = function (input) {
const regex = /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]+/;
if (regex.test(input)) throw new Error("輸入值包含特殊符號,請重新輸入");
};
或這樣寫
const isEmptyStr = function (input) {
if (input.trim().length === 0)
throw new Error("你沒有輸入東西喔..請重新輸入");
return input;
};
const isNagtive = function (input) {
if (+input < 0) throw new Error("這是一個負數,請重新輸入");
return input;
};
const includeSpecialChart = function (input) {
const regex = /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]+/;
if (regex.test(input)) throw new Error("輸入值包含特殊符號,請重新輸入");
};
export {
isEmptyStr,
isNagtive,
includeSpecialChart,
};
匯入時,如果要選擇部分匯入可以這樣做,這其實牽涉到物件解構賦值的過程:
import {
isEmptyStr,
isNagtive,
} from "../utilities/validateRule.js";
isEmptyStr(""); //Error: 你沒有輸入東西喔..請重新輸入
也可以一次匯出全部,把整個module當成一個物件使用,呼叫函式就像在使用物件的method,像這樣:
import * as validateRule from "../utilities/validateRule.js";
validateRule.isEmptyStr(""); //Error: 你沒有輸入東西喔..請重新輸入
而common js多應用於sever端,雖說如此,但因目前npm大多的套件還是以common js為主,所以其實很免不了會需要匯入cjs module作應用。
在cjs,每個模組有一個名為module的物件,當中有個叫做exports的屬性,其內容也是一個物件,我們可以藉由新增屬性到exports來匯出函式或變數。先來看看module長什麼樣子:
console.log(module);
在node執行檔案,可以在terminal看到module的內容,目前exports是個空物件。
const sum = (a, b) => a + b;
const difference = (a, b) => a - b;
module.exports.sum = sum;
module.exports.difference = difference;
console.log(module);
看一下exports的內容變成:
console.log(require("./cjsModule.js"));
既然回傳的是一個物件,要如何取出裡面的函式(或說method)就看個人喜歡怎麼取了,可以用物件的method,也可以用物件的解構:
//method
const functions = require("./cjsModule.js");
const resultSum = functions.sum(2, 3);
console.log(resultSum); //5
//obj destructuring
const { sum, difference } = require("./cjsModule.js");
const resultSum = sum(2, 3);
console.log(resultSum); //5
module.exports = (a, b) => a + b;
console.log(module);
故import的時候,就無需解構,可以直接存在一個變數內以便後續使用:
const functionSum = require("./cjsModule.js");
const resultSum = functionSum(2, 3);
console.log(resultSum); //5
基本上直接使用ES module的import語法匯入由common js匯出的模組是沒問題的,我目前也是這樣做,不過應該還是依套件說明文件,確定匯出的是什麼,再來決定匯入時該怎麼寫,如果是default export,匯入的名稱可以任選沒問題;但如果是named export就必須寫對名稱才能順利引入。
因為是程式小菜機所以使用的經驗也不是太多,若有其他需要注意的地方,還請各位大大給我一些指教,再次感謝!
ref
How to Import and Export Modules in Node JS (CommonJS)