BACK
Featured image of post 【Javascript】Require 與 Import 的區別

【Javascript】Require 與 Import 的區別

你有想過,我們在 javascript 要引入其他文件,有的時候使用 require,有的時候使用 import,這兩個方式有什麼差別?效能上又有什麼差別呢?本篇就來說明一下!

參考網站
參考網站
參考網站
參考網站
參考網站
參考網站


你有想過,我們在 JavaScript 要引入其他文件,有的時候使用 require,有的時候使用 import,這兩個方式有什麼差別?效能上又有什麼差別呢?本篇就來說明一下!


遵循的模塊化規範不同

require/exports 遵循 CommonJS 規範,主要用於 Node.js 伺服器端開發,以同步方式載入模組,也就是要載入完成後才能執行後面的程式碼。

import/export 則是 ES6 模組(ESM)標準,由 TC39 制定,屬於靜態編譯,編譯期就能解析依賴,瀏覽器與 Node.js 都原生支持(Node.js 14+)。若舊環境不支援,則可以透過 Babel + Webpack 轉譯。


出現的時間不同

  • require/exports:2010 年左右在 CommonJS 規範中出現,Node.js 廣泛採用。
  • import/export:ES6 (ES2015) 引入,2015 年之後才廣泛使用,Babel 是早期轉譯支援的重要工具。

現在 Node.js 14+ / 16+ 已原生支援 ES Module,不需要 Babel 也能直接使用 import/export


寫法與使用方式不同

CommonJS (require/exports)

1
2
3
const component = require('component')
exports.component = component
module.exports = component

ES6 Module (import/export)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import fs from 'fs'
import { readFile } from 'fs'
import { readFile as read } from 'fs'
import fs, { readFile } from 'fs'

export default fs
export const fs
export function readFile
export { readFile, read }
export * from 'fs'

動態載入(Dynamic Import)

靜態 import 必須是字面量字串,編譯期就要能確定模組路徑:

1
2
3
4
5
6
// ❌ 靜態 import 不能使用變數
const url = "./utils.js";
import url; // SyntaxError

// ✅ 靜態 import 正確用法
import myUtil from "./utils.js";

若需要 動態載入,可以使用 CommonJS 的 require() 或 ESM 的動態 import()

1
2
3
4
5
6
7
// 使用 require()(CommonJS)
const url2 = "./utils.js";
const myUtil2 = require(url2);

// 使用動態 import()(ESM)
const url3 = "./utils.js";
const myUtil3 = await import(url3);

說明

方法同步/非同步支援變數適用環境
import (靜態)靜態編譯ESM(編譯期)
require()同步CommonJS (Node.js)
await import()非同步ESM (Node.js / 瀏覽器)

Node.js 支援情況

  • Node.js 14.8+:動態 import() 正式可用(無需 flag)。
  • Node.js 16+ LTS:動態 import() 穩定,CommonJS 與 ESM 都可使用。
  • 靜態 import 與動態 import() 都可以取代 Babel 轉譯的需求,但 Babel/Webpack 仍用於瀏覽器或舊版兼容。

本質上的不同

  1. CommonJS 與 ES Module 輸出都是物件,但 ESM 支援 export default 與強綁定屬性
  2. require() 載入的是值或引用,靜態與動態都可以。
  3. 動態 import()require() 的動態行為對等,但非同步,不阻塞事件循環。

範例比較

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// counter.js
exports.count = 0
setTimeout(() => {
  console.log('increase count to', ++exports.count, 'in counter.js after 500ms')
}, 500)

// commonjs.js
const { count } = require('./counter')
setTimeout(() => {
  console.log('read count after 1000ms in commonjs is', count)
}, 1000)

// es6.js
import { count } from './counter'
setTimeout(() => {
  console.log('read count after 1000ms in es6 is', count)
}, 1000)

執行結果:

1
2
3
4
5
6
7
node commonjs.js
> increase count to 1 in counter.js after 500ms
> read count after 1000ms in commonjs is 0

babel-node es6.js  
> increase count to 1 in counter.js after 500ms
> read count after 1000ms in es6 is 1

效能差異

  • 靜態 import:編譯期執行。
  • require():同步載入,阻塞事件循環。
  • 動態 import():非同步載入,不阻塞事件循環。

在現代 Node.js 專案,如果能用靜態 import 就用,需動態載入才使用 require()await import()。效能差異微乎其微,但動態載入的同步/非同步行為會影響事件循環。


comments powered by Disqus