iT邦幫忙

2026 iThome 鐵人賽

DAY 2
0
JavaScript

研究 jQuery 4.0.0 原始碼:30 天 JavaScript 讀碼之旅系列 第 2

Day 2| jQuery 檔案的開頭就先用一個 `()` 包起來是為什麼,認識 IIFE 語法

  • 分享至 

  • xImage
  •  

查看完整的 jQuery 4.0.0 原始碼

一開始看到 jQuery 的開頭時,覺得它不像一般函式那樣直接寫完名稱,而是先包在 () 裡面:

開頭的程式碼大概是這樣子的:

(function (global, factory) {
  "use strict";

  if (typeof module === "object" && typeof module.exports === "object") {
    module.exports = factory(global, true);
  } else {
    factory(global);
  }
})(typeof window !== "undefined" ? window : this, function (window, noGlobal) {
  "use strict";

  // jQuery 的核心程式碼
});

最前面的左括號 ( 把 function 包起來,讓它成為函式表達式。 讓這個 function 變成函式表達式。因為 function 後面沒有寫名稱,所以它也是匿名函式。函式後面的 () 則是用來呼叫它。

看到這裡可以先分清楚,這段程式碼其實放了兩個函式。第一個是外層函式:

function (global, factory) {
  // 判斷環境,決定如何呼叫 factory
}

第二個則是被當成參數傳入的匿名函式,外層函式用 factory 這個參數接住它。

function (window, noGlobal) {
  // jQuery 的核心程式碼
}

外層函式在檔案載入時立即執行;內層的 factory 則先被當成一個函式值傳進去,等外層函式判斷完環境後,才由外層呼叫它。這也是 jQuery 把外層控制流程和內層核心程式碼分開的方式。

IIFE

剛剛的這種寫法稱為 IIFE (Immediately Invoked Function Expression,立即呼叫函式表達式)

先來看一般函式的寫法:

function greet(name) {
  console.log("Hello " + name);
}

greet("jQuery"); // 必須另外呼叫函式才會執行

IIFE 的寫法則是:

(function (name) {
  console.log("Hello " + name);
})("jQuery");

IIFE 就是把「建立函式」和「呼叫函式」寫在同一個表達式中。函式建立完成後會立即執行,不需要先替它取一個名稱,再從外部呼叫。

這裡的兩組括號也有不同的作用:

(function () {
  console.log("執行了");
})();

最前面的左括號 ( 把函式包起來,讓它成為函式表達式;最後面的 () 才是真正呼叫這個函式。也就是說,IIFE 並不是因為有括號就會自動執行,而是因為函式表達式後面緊接著呼叫括號。

理解 jQuery 為什麼要用 IIFE

我整理出了兩個主要原因:

  1. jQuery 需要在檔案載入時完成初始化,而且這個初始化流程只需要由 jQuery 自己執行。瀏覽器載入並執行 jquery-4.0.0.js 時,外層 IIFE 就會立即被呼叫,不需要使用者另外呼叫初始化函式。

如果自己的 script.js 會使用 $jQuery,就必須先載入 jQuery,再載入自己的 JS:

<script src="../jquery-4.0.0.js"></script>
<script src="./script.js"></script>

如果不用 IIFE,也可以把初始化寫成普通函式:

function initJQuery() {
  // 建立 jQuery
}

initJQuery();

但這樣會留下 initJQuery 這個函式名稱,而且外部還可以再次呼叫它。使用 IIFE 後,初始化函式沒有公開名稱,外部沒有這個函式的參考,也就不能直接再次呼叫同一個初始化入口。這很適合函式庫在載入時完成一次內部準備,只把真正要給使用者使用的 API 公開出去。

  1. IIFE 建立了一個函式作用域,讓 jQuery 的內部變數不會污染全域;jQuery 只把 jQuery 函式和 $ 別名公開給外部使用,其他內部變數則留在函式作用域中。

例如:

(function () {
  const secret = "只有函式裡知道";

  console.log(secret); // 函式裡可以使用
})();

console.log(secret); // 外部找不到這個變數 ReferenceError

secret 就像 jQuery 內部宣告的 arrslice,只在函式裡使用,不會直接出現在全域作用域中。

回到 jQuery 的程式碼,外層 IIFE 執行時,會把第一個引數傳給 global,把第二個引數,也就是 factory 函式,傳給外層的 factory 參數。接著外層才會呼叫 factory(global)factory(global, true)

小結

今天從 jQuery 檔案開頭的 () 開始,我認識了 IIFE,也理解了函式表達式、立即呼叫和函式作用域這幾個觀念。這些語法讓 jQuery 能在載入時執行初始化,同時把內部變數保護在函式裡。


上一篇
Day 1|學了一陣子的 JavaScript,但我真的懂它嗎?
系列文
研究 jQuery 4.0.0 原始碼:30 天 JavaScript 讀碼之旅2
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言