程式設計的 Hook(掛勾)是什麼?新手完整指南

最後更新:2025年12月29日基礎概念

在學程式的過程中,你可能會在很多地方看到「Hook」這個詞:

  • Git 有 Git Hooks
  • WordPress 有 Action Hooks 和 Filter Hooks
  • 很多框架都有 Lifecycle Hooks
  • 作業系統有 System Hooks

看起來到處都有 Hook,但它到底是什麼意思?

其實 Hook 是一個通用的程式設計概念,從 1990 年代的 Windows 作業系統就開始使用了。不管你現在學的是什麼語言或框架,理解 Hook 的核心概念,以後遇到任何「某某 Hook」都能快速上手。

這篇文章會用最白話的方式,帶你從零開始認識 Hook。

Hook 到底是什麼?

先聊聊「Hook」這個詞

你可能會好奇:為什麼叫「Hook(掛勾)」?

在台灣,講到「掛勾」我們通常會想到牆上那種用來掛東西的勾子。但在英文裡,Hook 更常見的意象其實是「魚鉤」🪝

理解這點,整個概念就通了。

用釣魚來解釋

想像你在河邊釣魚:

魚鉤的特性:

  • 放進水流中 → 不會擋住河水,水還是照流
  • 攔截你要的魚 → 特定的魚咬餌時,你就能把牠拉上來處理
  • 可以隨時放、隨時收 → 想釣就放勾,不想釣就收起來

在程式的世界裡,Hook 就像這個魚鉤

  • 程式流程 = 河水
  • 資料/事件 = 游過的魚
  • Hook = 你放進去的魚鉤
  • Hook 函式 = 魚上鉤後,你要怎麼處理牠

在程式碼裡是什麼樣子?

原本程式的流程:
步驟 A  步驟 B  步驟 C


放了 Hook 之後:
步驟 A  步驟 B  🪝【你的程式碼在這裡攔截】→ 步驟 C

程式還是照常跑,但在你放 Hook 的地方,會順便執行你寫的程式碼。

魚上鉤之後呢?

你可能會想:「魚被釣走了,不就消失了嗎?那資料不就不見了?」

好問題!其實 Hook 攔截到資料後,不一定要把魚「帶走」,通常有這幾種處理方式:

釣魚比喻看看是什麼魚,拍個照,然後放回去
程式世界監聽事件、記錄 log
釣魚比喻幫魚掛個標籤或做個記號,再放回河裡繼續游
程式世界Filter Hook,修改資料後讓它繼續傳遞
釣魚比喻這條魚有問題,攔截下來不放行
程式世界阻止事件,中斷原本的流程

大多數情況下,Hook 就像「河流中的檢查站」——資料游過來、停下來讓你檢查或處理一下,然後繼續往下游。

一句話定義

Hook 就是:在程式執行流程中「放一個魚鉤」,攔截你感興趣的資料或事件,然後做你想做的事。

這也是為什麼英文文件常用 “intercept”(攔截) 這個詞來描述 Hook 的行為——就像魚鉤攔截游過的魚一樣。

為什麼需要 Hook?

一個實際的問題

假設你在用一套別人開發的部落格系統,你想要加一個功能:

每次有人發表新文章時,自動發一封 Email 通知管理員

問題來了:你不能直接改別人的原始碼

為什麼不能改?

  • 改了之後,系統更新你的修改就會被覆蓋
  • 你可能改壞其他功能
  • 很難維護

Hook 怎麼解決這個問題?

回到釣魚的比喻:

你不能把整條河改道(改原始碼),但你可以在河邊放一個魚鉤(Hook),等特定的魚游過來時(發文事件),把牠攔截下來處理(發 Email)。

好的程式設計會預留「可以放魚鉤的位置」,讓你這樣做:

原本的發文流程:
使用者點發布  儲存到資料庫  顯示成功


放了 Hook 之後:
使用者點發布  儲存到資料庫  🪝【你的程式:發 Email】→ 顯示成功

你只要把「發 Email」的程式碼「勾」在那個點上,完全不用動到原本的程式碼。

Hook 的三大好處

釣魚比喻不用改變河流,只要放魚鉤
程式世界原本的程式怎麼更新都不影響你
釣魚比喻想釣就放鉤,不想釣就收起來
程式世界想用就掛上,不想用就拔掉
釣魚比喻你的魚鉤、你的事
程式世界你的程式碼和原本的分開管理

Hook 的常見類型

類型一:Before(之前)和 After(之後)

這是最常見的 Hook 類型,就像在河流的「上游」或「下游」放魚鉤。

🪝【Before Hook】← 在動作「之前」攔截
       
    原本的動作
       
🪝【After Hook】← 在動作「之後」攔截

用釣魚比喻

  • Before Hook:在魚游進某個區域「之前」就先攔截
  • After Hook:讓魚先游過去,「之後」再攔截

程式實例

  • Before:儲存資料「之前」,先檢查資料格式對不對
  • After:儲存資料「之後」,發一封確認信給使用者

類型二:Filter(過濾/修改)

這種 Hook 讓你可以「攔截並修改」正在傳遞的資料。就像抓到魚之後,幫牠清洗一下再放回去。

資料游過來  🪝【Filter Hook:攔截、修改】→ 修改過的資料繼續往下游

程式實例

  • 使用者輸入文字,經過 Filter 把髒話換成 ***
  • 使用者上傳圖片,經過 Filter 自動壓縮大小

Hook 在各種地方的應用

Hook 這個概念到處都在用,讓我們看看幾個常見的地方:

作業系統層級

這是 Hook 最早的應用場景,從 Windows 3.0(1990 年)就有了。

Windows 系統 Hook 的例子

做什麼用的攔截鍵盤輸入
做什麼用的攔截滑鼠動作
做什麼用的攔截系統訊息

哪些軟體在用?

  • 螢幕錄影軟體:攔截畫面來錄影
  • 密碼管理器:攔截輸入框來自動填入密碼
  • 快捷鍵工具:攔截特定按鍵組合來執行功能
  • 防毒軟體:攔截可疑的系統行為

版本控制:Git Hooks

如果你有用 Git 來管理程式碼,Git 本身就有內建 Hook 機制。

Hook 檔案放在專案的 .git/hooks/ 資料夾

常用的 Git Hooks

什麼時候觸發執行 commit 之前
可以拿來做什麼自動檢查程式碼風格
什麼時候觸發寫完 commit 訊息後
可以拿來做什麼檢查訊息格式
什麼時候觸發執行 push 之前
可以拿來做什麼自動跑測試
什麼時候觸發執行 merge 之後
可以拿來做什麼自動安裝新套件

實際例子

#!/bin/sh
# 檔案:.git/hooks/pre-commit
# 這段程式會在每次 commit 之前自動執行

echo "正在檢查程式碼..."

# 跑程式碼檢查
npm run lint

# 如果檢查失敗,就阻止 commit
if [ $? -ne 0 ]; then
  echo "❌ 程式碼檢查沒通過,請修正後再 commit"
  exit 1
fi

echo "✅ 檢查通過!"

網站系統:WordPress Hooks

WordPress 是全世界最多人用的網站系統,它的 Hook 機制設計得非常完整。

Action Hook(動作掛勾):在某個時機點「做某件事」

// 告訴 WordPress:每次發布文章後,執行 my_function
add_action('publish_post', 'my_function');

function my_function($post_id) {
    // 這裡的程式碼會在每次發文後自動執行
    send_email_to_admin($post_id);
}

Filter Hook(過濾掛勾):修改某個資料

// 告訴 WordPress:每次顯示文章內容時,先經過 add_footer
add_filter('the_content', 'add_footer');

function add_footer($content) {
    // 在每篇文章最後加上一段文字
    return $content . '<p>感謝閱讀!</p>';
}

後端框架的 Hook

很多後端框架也有類似的機制,有時候叫 Hook,有時候叫 Middleware 或 Lifecycle。

資料庫操作的 Hook(以 Sequelize + PostgreSQL 為例)

const { Sequelize, DataTypes } = require('sequelize');
const sequelize = new Sequelize('postgresql://...');

const User = sequelize.define('User', {
  name: DataTypes.STRING,
  password: DataTypes.STRING
}, {
  hooks: {
    // Before Hook:儲存「之前」自動加密密碼
    beforeCreate: async (user, options) => {
      user.password = await hashPassword(user.password);
      console.log('密碼已加密!');
    },

    // After Hook:刪除「之後」記錄 log
    afterDestroy: (user, options) => {
      console.log('使用者已刪除:', user.name);
    }
  }
});

網頁請求的 Hook(Middleware)

// 每個請求進來都會先經過這裡
app.use((req, res, next) => {
  console.log('收到請求:', req.url);
  console.log('時間:', new Date());
  next(); // 繼續往下執行
});

前端框架的 Lifecycle Hooks

前端框架通常會提供「生命週期 Hook」,讓你在元件的不同階段執行程式碼。

什麼是元件的生命週期?

在前端框架裡,畫面是由一個一個「元件」組成的(你可以把元件想像成一塊一塊的積木)。每個元件從出現到消失,會經歷幾個階段,這就叫做「生命週期」:

用演員比喻

把元件想像成一個演員:

演員比喻演員準備上台
你可以在這時做什麼初始化資料、設定預設值
演員比喻演員登場,觀眾看到了
你可以在這時做什麼去 API 抓資料、啟動計時器
演員比喻演員換裝、換台詞
你可以在這時做什麼根據新資料重新計算、更新畫面
演員比喻演員下台,表演結束
你可以在這時做什麼清理計時器、取消訂閱、釋放資源

為什麼需要 Lifecycle Hooks?

想像一個情境:你有一個顯示即時股價的元件

  • 掛載時:要啟動一個計時器,每 5 秒去抓最新股價
  • 移除時:如果使用者切換到別的頁面,元件消失了,但計時器還在跑,就會浪費資源甚至出錯

有了 Lifecycle Hook,你可以:

元件掛載  🪝 Hook:啟動計時器,開始抓股價

    
    
元件移除  🪝 Hook:清掉計時器,停止抓股價

這樣就能確保資源被正確管理,不會有「元件消失了但計時器還在跑」的問題。

容易搞混的相似概念

學 Hook 的時候,你可能會遇到一些看起來很像的名詞。讓我們繼續用河流釣魚的比喻來釐清它們的差別。

Hook vs Callback(回呼函式)

這兩個概念非常相似,很多人會搞混。

Hook系統預留好擴充點,你把程式碼「掛」上去
Callback你把函式「傳」給別人,讓別人在適當時機呼叫
Hook你等系統來觸發
Callback你主動傳遞函式
Hook通常用「註冊」的方式
Callback通常當作參數傳入

用河流比喻

  • Hook:河邊本來就有設計好的「釣魚平台」🎣,你只要去那邊放下魚鉤,等魚來就好
  • Callback:你自己帶了一個魚鉤,交給船長說「如果有魚經過,用這個鉤幫我抓」

程式碼對比

// Callback:你主動把函式(魚鉤)傳進去

fetchData(url, function(data) {
  console.log('資料回來了', data);
});


// Hook:系統有預留釣魚點,你去那邊註冊

WordPress: add_action('publish_post', myFunction);
Git: 把腳本放到 .git/hooks/pre-commit
Sequelize: hooks: { beforeCreate: myFunction }

結論:其實很像!Hook 內部通常就是用 Callback 來實現的。主要差別在於「誰設計了這個機制」——Hook 是河邊預先蓋好的釣魚平台,Callback 是你自己帶魚鉤請別人幫忙。

Hook vs Middleware(中介軟體)

這兩個在 Web 開發中很常見,概念也很接近。

Hook在特定時機插入程式碼
Middleware在請求處理流程中插入程式碼
Hook廣泛,各種場景都有
Middleware主要用在 Web 框架
Hook可能只在特定事件觸發
Middleware通常每個請求都會經過

用河流比喻

  • Hook:在河邊放魚鉤 🪝,只有特定的魚(事件)咬餌時才會觸發
  • Middleware:在河流中蓋了好幾道「水閘門」🚧,每一滴水(每個請求)都必須依序通過每一道閘門
Hook:
河水流動  大部分魚游過  🪝 只有特定的魚被攔截  河水繼續流


Middleware:
河水流動  🚧閘門1  🚧閘門2  🚧閘門3  每滴水都要過每道閘門
            (紀錄)    (過濾)    (檢查)

Middleware 的特色:每個請求都要經過

// Express Middleware:每個請求都會依序經過每道閘門

app.use(紀錄Log);      // 第一道閘門
app.use(檢查登入);      // 第二道閘門
app.use(驗證權限);      // 第三道閘門

// ↓ 然後才到達目的地

Hook 的特色:只攔截特定事件

// Hook:只有特定的魚(事件)才會觸發

beforeSave  只有「儲存」這條魚游過來時才攔截
afterDelete  只有「刪除」這條魚游過來時才攔截

結論:Middleware 像是河流中的「水閘門」,每滴水都要經過;Hook 像是河邊的「魚鉤」,只攔截特定的魚。Middleware 可以說是 Hook 概念在「Web 請求處理」上的特殊應用。

Hook vs Event(事件)

這兩個看起來都是「某件事發生時執行程式碼」,但有個關鍵差別。

Hook可以攔截、修改、甚至阻止原本的動作
Event通常只是通知你有事發生
Hook可以深度介入流程
Event比較像旁觀者
Hook通常可以
Event通常不行,事情已經發生了

用河流比喻

  • Hook(魚鉤):你把魚鉤放進河裡 🪝,魚游過來時你可以:
  • 看一眼就放走
  • 幫牠做記號再放走
  • 不讓牠繼續往下游(攔截)
  • Event(事件):你在河邊裝了一個「感應器」📡,魚游過去的時候會發出「叮!」的通知聲。但魚已經游過去了,你只是被通知,無法攔截牠。
Hook:
魚游過來  🪝 攔截!→ 你決定要怎麼處理  放走 or 不讓牠過


Event:
魚游過來  魚游過去了  📡「叮!有魚經過」→ 你只是被通知

程式碼對比

// Event:魚已經游過去了,你只是被通知
button.addEventListener('click', () => {
  console.log('按鈕被點了!');  // 點擊已經發生,你只是收到通知
});

// Hook:魚還沒游過去,你可以決定要不要放行
form.onsubmit = (e) => {
  if (!isValid) {
    e.preventDefault();  // 不讓這條魚過去!
    return false;
  }
};

更明顯的例子

// Event 風格:魚已經游走了,你只是被通知
database.on('saved', (data) => {
  console.log('資料已儲存', data);  // 已經存了,你只是被通知
});

// Hook 風格:魚還在你手上,你可以決定怎麼處理
database.beforeSave((data) => {
  if (data.price < 0) {
    throw new Error('價格不能是負數!');  // 不讓這條魚過去!
  }
  data.updatedAt = new Date();  // 幫魚做個記號
  return data;  // 放走,讓牠繼續游
});

結論:Event 是河邊的「感應器」,告訴你有魚經過;Hook 是「魚鉤」,讓你可以攔截、修改、甚至阻止魚繼續往下游。

總結比較

河流比喻魚鉤 🪝
關鍵特色攔截特定的魚,可修改、可阻止
河流比喻你帶來請別人用的魚鉤
關鍵特色你主動提供工具
河流比喻河中的水閘門 🚧
關鍵特色每滴水都要經過,串聯執行
河流比喻河邊的感應器 📡
關鍵特色通知有魚經過,但無法攔截

其實這些概念有很多重疊的地方,不用太糾結它們的邊界。重要的是理解它們各自強調的重點!

不同領域的 Hook 命名習慣

認識這些命名慣例,遇到新框架時可以更快理解:

命名方式時機 + 動作
例子pre-commit、post-merge
命名方式add_action、add_filter
例子add_action('init', ...)
命名方式pre/post + 動作
例子pre('save')、post('remove')
命名方式生命週期名稱
例子mounted、created、destroyed
命名方式事件類型 + Hook
例子KeyboardHook、MouseHook

自己設計 Hook 的簡單範例

如果你想在自己的程式裡實現 Hook 機制,概念其實很簡單:

// 一個超簡單的 Hook 系統

// 1. 建立一個地方存放所有掛上來的函式
const hooks = {
  beforeSave: [],
  afterSave: []
};

// 2. 提供「掛載」的方法
function addHook(hookName, fn) {
  hooks[hookName].push(fn);
}

// 3. 在適當的時機「觸發」Hook
function saveData(data) {
  // 觸發 beforeSave hook
  hooks.beforeSave.forEach(fn => fn(data));

  // 執行真正的儲存
  console.log('儲存資料:', data);

  // 觸發 afterSave hook
  hooks.afterSave.forEach(fn => fn(data));
}

// 使用方式:
addHook('beforeSave', (data) => {
  console.log('準備儲存...');
});

addHook('afterSave', (data) => {
  console.log('儲存完成,發送通知!');
});

saveData({ name: 'Alice' });

// 輸出:
// 準備儲存...
// 儲存資料:{ name: 'Alice' }
// 儲存完成,發送通知!

總結

核心觀念

記住釣魚的比喻,Hook 就很好理解了:

程式程式執行流程
程式資料、事件、訊息
程式Hook
程式Hook 函式
  1. Hook 是通用概念:不屬於任何特定語言或框架,到處都在用
  2. Hook 的本質:在程式流程中「放一個魚鉤」,攔截你感興趣的東西
  3. Hook 的價值:不用改河道(原始碼),只要放魚鉤就能做事

Hook 出現的地方

作業系統    Windows/Linux 系統 Hook
版本控制    Git Hooks
網站系統    WordPress Hooks  
後端框架    Middleware、Lifecycle Hooks
前端框架    Lifecycle Hooks

遇到新的 Hook 時,問自己三個問題

當你在學新工具遇到「某某 Hook」時,問自己:

  1. 什麼時候可以放鉤? → 了解觸發時機
  2. 能攔截到什麼? → 了解能處理的資料或事件
  3. 能不能阻止魚繼續游? → 了解能否中斷原本的流程

搞懂這三點,你就掌握那個 Hook 了!

💡 小提醒:不同框架對 Hook 的實作細節可能不同,但核心概念都是一樣的。學會這個概念,以後遇到任何 Hook 都不怕!

目前還沒有留言,成為第一個留言的人吧!

發表留言

留言將在審核後顯示。