跳至主要内容

5 篇文章 含有標籤「模組」

檢視所有標籤

JavaScript 模組系統:CommonJS 與 AMD 入門教學 | 學習筆記

· 閱讀時間約 4 分鐘
kdchang

前言

在 JavaScript 早期,所有程式碼通常寫在單一文件中,這樣的方式在小型專案中或許可行,但當應用程式變得更大、更複雜時,這種結構會導致管理困難。因此,模組化的概念被引入,允許開發者將程式碼拆分成可重複使用的獨立部分,提高可維護性與擴展性。

在 ES6 標準推出之前,JavaScript 主要依賴 CommonJS(CJS)Asynchronous Module Definition(AMD) 來實現模組化。這兩種模組系統有不同的設計理念與應用場景,以下將詳細介紹其特性與實作方式。


1. CommonJS(CJS)—— Node.js 的標準模組系統

概述

CommonJSNode.js 所採用,主要用於伺服器端開發。它的核心概念是 同步載入(Synchronous Loading),這意味著模組在執行時會逐步載入,而不是並行載入。

CommonJS 主要透過 require() 來載入模組,並使用 module.exportsexports 來匯出模組內容。

CommonJS 語法

(1) 定義模組(匯出)

// math.js
const pi = 3.14159;

function add(a, b) {
return a + b;
}

function subtract(a, b) {
return a - b;
}

// 匯出模組
module.exports = {
pi,
add,
subtract
};

(2) 使用模組(載入)

// main.js
const math = require('./math');

console.log(math.pi); // 3.14159
console.log(math.add(10, 5)); // 15
console.log(math.subtract(20, 8)); // 12

CommonJS 特點

優點: 適用於伺服器端(Node.js),可輕鬆管理模組與依賴。
簡單直覺的 require()module.exports 語法
支援循環依賴(Circular Dependencies),當兩個模組互相依賴時,仍能正確解析。

缺點: 同步載入(Synchronous Loading),不適合瀏覽器端,因為會阻塞執行緒,影響頁面效能。
不支援瀏覽器環境,需使用 Webpack 或 Browserify 來轉換為瀏覽器可用的程式碼。


2. AMD(Asynchronous Module Definition)—— 適用於瀏覽器的模組系統

概述

AMD 是專為 瀏覽器環境 設計的模組系統,解決了 CommonJS 無法在前端環境直接運作的問題。AMD 的關鍵特點是 非同步載入(Asynchronous Loading),允許模組在需要時才載入,避免影響頁面效能。

AMD 主要使用 define() 來定義模組,require() 來載入模組。

AMD 語法

(1) 定義模組(匯出)

// math.js
define([], function () {
const pi = 3.14159;

function add(a, b) {
return a + b;
}

function subtract(a, b) {
return a - b;
}

return {
pi,
add,
subtract
};
});

(2) 使用模組(載入)

// main.js
require(['math'], function (math) {
console.log(math.pi); // 3.14159
console.log(math.add(5, 6)); // 11
});

AMD 特點

優點: 適用於瀏覽器環境,支援非同步載入,提高效能。
使用 define()require() 來管理模組,能夠載入多個依賴。
非同步執行,適合大型應用程式,減少載入時間。

缺點: 語法較繁瑣,比 CommonJS 需要更多設定。
需要 RequireJS 來執行,瀏覽器無法直接支援 AMD。


3. CommonJS vs AMD vs ES Modules(ESM)

特性CommonJS(CJS)AMDES Modules(ESM)
適用環境Node.js瀏覽器瀏覽器 & Node.js
載入方式require()require()import/export
同步/非同步同步(Synchronous)非同步(Asynchronous)靜態解析(Static)
優勢簡單易用,適合伺服器端適用瀏覽器,非同步載入現代標準,支援 Tree Shaking
限制不適合瀏覽器需要 RequireJS需要 ES6 瀏覽器或 Node.js 12+

4. CommonJS 與 AMD 的使用時機

  • 當開發伺服器端應用程式時,建議使用 CommonJS,因為它與 Node.js 相容性最佳。
  • 當開發前端應用時,AMD 是一種選擇,但目前更推薦使用 ES Modules(ESM)
  • 現代 JavaScript 建議使用 ES Modules(import/export),因為它已經成為標準,並且同時支援瀏覽器與 Node.js 環境。

5. 結論

在 JavaScript 模組化的歷史發展中,CommonJS 被廣泛用於 伺服器端,而 AMD 則主要針對 瀏覽器環境 設計。隨著 ES6 的 ES Modules(ESM)標準化,許多開發者已經轉向 ESM,因為它在語法上更直覺,並且可以同時適用於前端與後端。

雖然 CommonJS 和 AMD 仍然在某些專案中使用,但未來趨勢將逐漸轉向 ES Modules。因此,對於新專案,建議 優先使用 ES Modules(import/export),而對於舊專案或特定環境(如 Node.js 早期版本),仍可能需要使用 CommonJS 或 AMD。

JavaScript 模組(Module)入門教學筆記 | 學習筆記

· 閱讀時間約 4 分鐘
kdchang

1. 什麼是 JavaScript 模組?

JavaScript 模組(Module)是一種將程式碼拆分成多個獨立文件,並在不同文件間共享和管理程式碼的方式。透過模組化的設計,可以讓程式碼更具結構性、可讀性與可維護性。

在 ES6(ECMAScript 2015)之前,JavaScript 主要透過 IIFE(立即執行函式)、CommonJS 或 AMD 來模組化程式碼。而 ES6 之後,JavaScript 原生支援 ES Modules(ESM),提供 importexport 來管理模組。


2. 為什麼需要模組?

  1. 避免全域變數污染
    • 模組能夠封裝變數,避免不同程式碼區塊互相影響。
  2. 提高可維護性
    • 讓程式碼結構更清晰,拆分不同的功能至獨立文件中。
  3. 支援程式碼重用
    • 可在多個專案中共享相同的模組,避免重複開發。
  4. 支援延遲載入(Lazy Loading)
    • 透過動態 import(),按需載入模組,提高效能。

3. ES6 模組語法

在 ES6 中,我們主要使用 exportimport 來定義和載入模組。

(1) export 的使用

命名匯出(Named Export)

// math.js
export const pi = 3.14159;
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}

預設匯出(Default Export)

// greeting.js
export default function sayHello(name) {
return `Hello, ${name}!`;
}

(2) import 的使用

匯入命名匯出

// main.js
import { pi, add, subtract } from "./math.js";

console.log(pi); // 3.14159
console.log(add(5, 3)); // 8
console.log(subtract(10, 4)); // 6

匯入預設匯出

// main.js
import sayHello from "./greeting.js";

console.log(sayHello("Alice")); // "Hello, Alice!"

匯入所有模組內容

// main.js
import * as math from "./math.js";

console.log(math.pi); // 3.14159
console.log(math.add(2, 3)); // 5

使用 as 重新命名

import { add as sum, subtract as minus } from "./math.js";

console.log(sum(10, 5)); // 15
console.log(minus(10, 5)); // 5

4. ES 模組的特性

  1. 靜態解析(Static Analysis)

    • importexport 必須在頂層作用域,不能在條件語句或函式內部。
    • 在編譯時(compile time)解析模組,而不是執行時(runtime)。
  2. 模組作用域

    • 每個模組都有自己的作用域,變數不會污染全域作用域。
  3. 自動使用嚴格模式(Strict Mode)

    • ES6 模組內部自動啟用 "use strict",無需手動指定。

5. 動態載入模組

有時候我們希望在特定條件下載入模組,而不是在程式開始時就載入所有模組。這時可以使用 import() 來動態載入。

if (true) {
import("./math.js").then((math) => {
console.log(math.add(5, 10)); // 15
});
}
  • import() 回傳一個 Promise,當模組載入完成後執行回調函式。
  • 這種方式適合懶加載(Lazy Loading)與條件性載入。

6. varlet 在模組中的行為

在模組內,變數 var 仍然會被提升(Hoisting),但 letconst 具有區塊作用域。

// module.js
var globalVar = "I am global";
let localVar = "I am local";
// main.js
import "./module.js";

console.log(globalVar); // "I am global" (因為 var 會提升到全域)
console.log(localVar); // ReferenceError: localVar is not defined

7. 在瀏覽器與 Node.js 環境使用 ES 模組

(1) 瀏覽器

在 HTML 文件中,使用 <script type="module"> 來載入 ES6 模組。

<script type="module">
import { add } from "./math.js";
console.log(add(10, 5));
</script>

(2) Node.js

Node.js 14+ 版本支援 ES 模組,但需要:

  • 檔案副檔名改為 .mjs
  • package.json 設定 "type": "module"
{
"type": "module"
}
// math.mjs
export function multiply(a, b) {
return a * b;
}
// main.mjs
import { multiply } from "./math.mjs";
console.log(multiply(4, 5)); // 20

8. 模組引入方式整理

環境引入方式
瀏覽器(ESM)<script type="module">
Node.js(ESM)import { foo } from './module.mjs'
Node.js(CommonJS)const foo = require('./module.js')
動態載入(Lazy Load)import('./module.js').then(...)
重新命名import { foo as newFoo } from './module.js'
匯入所有內容import * as mod from './module.js'

9. 結論

  1. ES 模組是 JavaScript 原生模組系統,使用 importexport 來管理程式碼。
  2. 模組有助於提升可讀性與可維護性,避免全域變數污染。
  3. 動態載入(import())可以優化效能,適合延遲載入模組。
  4. 瀏覽器與 Node.js 都支援 ES6 模組,但 Node.js 需要 .mjspackage.json 設定 "type": "module"
  5. 模組可以透過不同方式引入,根據環境選擇適合的方法。

掌握 JavaScript 模組的概念,能夠讓你更有效地開發與維護大型專案。

MongoDB 入門教學筆記 | 學習筆記

· 閱讀時間約 4 分鐘
kdchang

前言

在現代應用程式開發中,資料儲存已不再侷限於傳統的關聯式資料庫(如 MySQL、PostgreSQL)。特別是在處理非結構化資料、需要高延展性或頻繁 schema 變動的應用場景中,NoSQL 資料庫逐漸成為主流選擇。

其中,MongoDB 是最受歡迎的 NoSQL 資料庫之一。它採用文件型(Document-Oriented)結構,使用 JSON 類型格式(實際為 BSON)儲存資料,讓開發者能更靈活地設計資料模型與操作資料。MongoDB 強調可擴展性、彈性資料結構與高效查詢能力,廣泛應用於 Web 開發、物聯網、大數據處理等領域。


重點摘要

  • MongoDB 是什麼?

    • 開源的 NoSQL 文件資料庫,使用 BSON 格式儲存資料。
    • 資料以「資料庫 → 集合(Collection)→ 文件(Document)」的層級組織。
    • 每個文件(Document)類似於 JSON 結構,支援巢狀資料與陣列。
  • 主要特性

    • 文件型資料儲存(更彈性且接近開發者熟悉的物件結構)
    • 無需預先定義 Schema,可動態變更欄位
    • 垂直與水平延展能力佳
    • 提供複寫與分片支援(Replica Set、Sharding)
    • 強大的查詢語言,支援索引、聚合、全文搜尋
  • 應用場景

    • RESTful API 後端儲存(如 Node.js + Express 專案)
    • 快速原型設計與資料模型測試
    • 高並發讀寫需求(例如留言板、商品評論系統)
    • 資料格式變動頻繁的場景(如 IoT 裝置紀錄)

安裝與啟動

1. 安裝 MongoDB(本機)

Mac 使用者(使用 Homebrew):

brew tap mongodb/brew
brew install mongodb-community@7.0
brew services start mongodb/brew/mongodb-community

Windows / Linux: 可前往 https://www.mongodb.com/try/download/community 下載對應版本。

2. 啟動 MongoDB

mongod

啟動成功後,預設會在 mongodb://localhost:27017 提供本地服務。

3. 開啟 Mongo Shell(或使用 MongoDB Compass GUI)

mongosh

進入後會看到互動式 shell 環境,開始操作你的資料庫。


MongoDB 基本操作(Shell 範例)

1. 建立 / 切換資料庫

use blog

2. 建立集合(Collection)與新增文件(Document)

db.posts.insertOne({
title: 'MongoDB 入門教學',
author: 'KD',
tags: ['database', 'nosql', 'mongodb'],
published: true,
created_at: new Date(),
});

插入文件時自動建立集合與資料庫。

3. 查詢文件

db.posts.find();
db.posts.find({ author: 'KD' });
db.posts.findOne({ published: true });

支援條件、邏輯查詢、排序、分頁等功能:

db.posts.find({ published: true }).sort({ created_at: -1 }).limit(5);

4. 更新文件

db.posts.updateOne({ title: 'MongoDB 入門教學' }, { $set: { published: false } });

支援 $set, $inc, $push, $unset 等更新操作符。

5. 刪除文件

db.posts.deleteOne({ title: 'MongoDB 入門教學' });

使用 Mongoose 操作(Node.js 範例)

在 Node.js 專案中,常使用 mongoose 封裝操作 MongoDB。

1. 安裝套件

npm install mongoose

2. 建立連線與定義模型

const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/blog');

const postSchema = new mongoose.Schema({
title: String,
author: String,
tags: [String],
published: Boolean,
created_at: { type: Date, default: Date.now },
});

const Post = mongoose.model('Post', postSchema);

3. 實際使用範例

新增資料:

const newPost = new Post({
title: '用 Node.js 操作 MongoDB',
author: 'KD',
tags: ['nodejs', 'mongodb'],
published: true,
});

await newPost.save();

查詢資料:

const posts = await Post.find({ published: true }).limit(5);

更新資料:

await Post.updateOne({ title: '用 Node.js 操作 MongoDB' }, { published: false });

刪除資料:

await Post.deleteOne({ title: '用 Node.js 操作 MongoDB' });

聚合(Aggregation)入門

MongoDB 提供強大的 Aggregation Pipeline 功能,可進行統計、分組、轉換。

範例:統計作者貼文數量

db.posts.aggregate([{ $group: { _id: '$author', count: { $sum: 1 } } }, { $sort: { count: -1 } }]);

總結

MongoDB 以其彈性、易用與高延展性,成為許多現代應用的首選資料庫,特別是在快速開發、微服務架構或大數據處理場景中表現優異。透過簡單的 JSON 結構與強大的查詢能力,即使不熟 SQL 的開發者也能快速上手,打造穩定且具擴展性的資料儲存系統。

初學者可先從基本的增刪查改練習起,逐步熟悉資料結構與聚合操作,再延伸到使用 Mongoose 開發 REST API,或搭配 GraphQL、Next.js 等前後端整合工具,深入打造現代 Web 應用。

Node.js Express.js 入門教學筆記 | 學習筆記

· 閱讀時間約 3 分鐘
kdchang

1. 簡介

Express.js 是一個基於 Node.js 的 Web 應用框架,提供簡潔且靈活的 API,適用於建立伺服器端應用程式。它可以用來開發 RESTful API、Web 應用或後端服務。

為什麼選擇 Express.js?

  • 輕量且易於學習
  • 擴展性高
  • 內建強大的中介軟體(Middleware)系統
  • 支援各種範本引擎(例如:EJS, Pug)

2. 安裝與專案初始化

安裝 Node.js

在開始使用 Express.js 之前,請先安裝 Node.js

初始化專案

建立一個新的專案資料夾,然後執行以下指令來初始化 Node.js 專案:

mkdir express-app
cd express-app
npm init -y

安裝 Express.js

npm install express

3. 建立第一個 Express 伺服器

建立 server.js 檔案,並加入以下程式碼:

const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
res.send('Hello, Express!');
});

app.listen(port, () => {
console.log(`Server is running at http://localhost:${port}`);
});

啟動伺服器

node server.js

然後在瀏覽器打開 http://localhost:3000/,應該可以看到 Hello, Express!

4. 中介軟體(Middleware)

Express 提供 Middleware,可用來處理請求與回應,例如:解析請求體、驗證請求等。

使用 express.json() 解析 JSON

app.use(express.json());

建立自訂中介軟體

app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
});

5. 路由(Routing)

Express 允許定義不同的 HTTP 方法對應不同的路由。

GET 路由

app.get('/api/users', (req, res) => {
res.json([{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]);
});

POST 路由

app.post('/api/users', (req, res) => {
const newUser = req.body;
res.status(201).json(newUser);
});

參數化路由

app.get('/api/users/:id', (req, res) => {
const userId = req.params.id;
res.json({ id: userId, name: `User ${userId}` });
});

6. 靜態檔案服務

Express 可用來提供靜態檔案,例如 HTML、CSS、JavaScript。

app.use(express.static('public'));

然後在 public/index.html 中放入 HTML,即可直接透過 http://localhost:3000/index.html 存取。

7. 錯誤處理

Express 提供錯誤處理中介軟體,可用來處理應用中的錯誤。

app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ message: 'Something went wrong!' });
});

8. 整合 MongoDB

可以使用 mongoose 來與 MongoDB 互動。

安裝 mongoose

npm install mongoose

連接 MongoDB

const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/mydatabase', {
useNewUrlParser: true,
useUnifiedTopology: true
}).then(() => {
console.log('Connected to MongoDB');
}).catch(err => {
console.error('MongoDB connection error:', err);
});

9. 部署 Express 應用

可以使用 PM2 來管理 Express 伺服器。

安裝 PM2

npm install -g pm2

啟動應用

pm2 start server.js --name express-app

10. 總結

透過這篇筆記,你已經學會:

  1. 安裝與初始化 Express.js
  2. 建立基本 Web 伺服器
  3. 使用中介軟體與路由
  4. 提供靜態檔案
  5. 錯誤處理
  6. 整合 MongoDB
  7. 部署 Express 應用

這些概念是 Express.js 開發的基礎,熟練後可以進一步學習 JWT 認證、WebSocket、GraphQL 等進階技術!

Alpine.js 入門教學筆記 | 學習筆記

· 閱讀時間約 4 分鐘
kdchang

1. 什麼是 Alpine.js?

Alpine.js 是一個輕量級的 JavaScript 框架,專為增強 HTML 標記而設計。它的語法靈感來自 Vue.js,但更加簡潔,適用於需要簡單互動的網頁。

它的主要特點包括:

  • 使用 HTML 屬性直接定義行為
  • 不需要額外的構建工具
  • 易於學習和使用
  • 與其他框架(如 Vue、React)兼容

2. 安裝與引入

使用 Alpine.js 最簡單的方法是透過 CDN 引入。

<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Alpine.js 入門</title>
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
</head>
<body>
<h1>Alpine.js 教學</h1>
</body>
</html>

3. 基本語法與應用

3.1 x-data

x-data 屬性用於定義 Alpine.js 的組件狀態。

<div x-data="{ message: 'Hello, Alpine!' }">
<p x-text="message"></p>
</div>

這段程式碼會顯示 Hello, Alpine!,並且 x-text 會自動更新內容。

3.2 x-bind

x-bind 允許綁定 HTML 屬性。

<div x-data="{ color: 'red' }">
<p x-bind:style="'color: ' + color">這是一段紅色文字</p>
</div>

3.3 x-on

x-on 用於事件監聽,例如點擊事件。

<div x-data="{ count: 0 }">
<button x-on:click="count++">增加</button>
<p>計數:<span x-text="count"></span></p>
</div>

3.4 x-model

x-model 允許雙向綁定表單元素。

<div x-data="{ name: '' }">
<input type="text" x-model="name" placeholder="輸入你的名字">
<p>你好,<span x-text="name"></span></p>
</div>

3.5 x-show

x-show 控制元素顯示或隱藏。

<div x-data="{ isVisible: true }">
<button x-on:click="isVisible = !isVisible">切換顯示</button>
<p x-show="isVisible">這段文字可以顯示或隱藏</p>
</div>

3.6 x-if

x-if 會動態新增或移除元素(比 x-show 更影響 DOM)。

<div x-data="{ isVisible: true }">
<button x-on:click="isVisible = !isVisible">切換</button>
<template x-if="isVisible">
<p>這是一段可動態新增或刪除的文字</p>
</template>
</div>

3.7 x-for

x-for 用於迭代陣列。

<div x-data="{ items: ['蘋果', '香蕉', '橘子'] }">
<ul>
<template x-for="item in items" :key="item">
<li x-text="item"></li>
</template>
</ul>
</div>

3.8 計時器與非同步操作

Alpine.js 支援 setTimeoutfetch 等 JavaScript 方法。

<div x-data="{
message: '載入中...',
async fetchData() {
let response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
let data = await response.json();
this.message = data.title;
}
}" x-init="fetchData">
<p x-text="message"></p>
</div>

4. Alpine.js 與 Tailwind CSS

Alpine.js 常與 Tailwind CSS 搭配使用,打造簡潔的 UI。

<div x-data="{ open: false }" class="p-5">
<button x-on:click="open = !open" class="bg-blue-500 text-white px-4 py-2 rounded">
切換選單
</button>
<ul x-show="open" class="mt-2 border p-2">
<li>選單 1</li>
<li>選單 2</li>
<li>選單 3</li>
</ul>
</div>

5. Alpine.js 進階應用

5.1 Alpine.store

Alpine.store 可用於全域狀態管理。

<script>
document.addEventListener('alpine:init', () => {
Alpine.store('app', { count: 0 });
});
</script>

<div x-data>
<button x-on:click="$store.app.count++">增加</button>
<p>計數:<span x-text="$store.app.count"></span></p>
</div>

5.2 Alpine.plugin

Alpine.js 提供外掛支援,例如 persist(本地儲存)。

<script src="https://cdn.jsdelivr.net/npm/@alpinejs/persist@3.x.x/dist/cdn.min.js"></script>
<script>
document.addEventListener('alpine:init', () => {
Alpine.plugin(Alpine.persist);
});
</script>

<div x-data="{ count: $persist(0) }">
<button x-on:click="count++">增加</button>
<p>計數:<span x-text="count"></span></p>
</div>

6. 總結

Alpine.js 是一個靈活且輕量的框架,適合用於簡單互動需求,如表單驗證、選單切換、即時更新內容等。它不需要複雜的配置,能夠快速增強靜態 HTML 頁面。

如果你的專案需要更強大的功能,可以考慮與 Vue.js 或 React 搭配,或在更大規模的應用中使用其他框架。