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

【Javascript】Require 與 Import 的區別

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

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

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


遵循的模塊化規範不同

模塊化規範:意思是 javascript 提供一種模塊編寫、模塊依賴、模塊運行的方案 —— 全局變數就是他的模塊化規範。

require/exports 在 2010 年左右出現於野生規範中,什麼是野生規範?就是由 javascript 社群內的開發者們自己擬定並被大家承認、廣泛使用的規範,遵循 CommonJS 規範為的是伺服器端開發設計的,而 node.js 則是 CommonJS 規範的實現,CommonJS 規範以同步的方式載入模組(Module),也就是要載入完成後,才能執行後面的程式。

import/export 則是名門正派透過 TC39 制定的新 ECMAScript 版本,即為 ES6 (ES2015) 中包含進來的,靜態編譯,在編譯過程中執行,如果遇到不支援 ES6 的情況下,就會需要 webpack + babel 來轉譯成 require/exports


出現的時間不同

隨著 node.js 的流行與 Browsersify 的興起,運行時異步逐漸被 require/exports 建構時模塊合併分塊所替代,Wrapper 函數再也不需要了,2014 年 Webpack 還是個新玩意兒,現在已經是前端必備神器了。

Browsersify、Webpack 一開始的目的就是用來打包 CommonJS 模塊。

CommonJS 作為 node.js 的規範一直沿用至今。由於 npm 上的 CommonJS 的庫眾多,以及 CommonJS 與 ES6 之間的差異, node.js 無法直接兼容 ES6,所以現階段 require/exports 仍然是必要的。

import/export 相對就晚了許多,被大家所熟知與使用也是 2015 年之後的事了,這其實多虧了 babel (原項目為 6to5,後來更名為 babel) 這個神項目。由於有了 babel,將還未被各瀏覽器、node.js 直接支持的 ES6 Module 編譯為 ES5 的 CommonJS —— 也就是 require/exports 這種寫法,Webpack 安上 babel-loader 這個翅膀才開始高飛,大家也才可以稱自己在使用 ES6!

這也就是為什麼上面說到:require/exports 是必要的,因為目前你編寫的 import/export,最終都是編譯為 require/exports 來執行!


寫法與使用方式不同

require/exports 只有以下簡單的寫法:

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

import/export 的寫法就相當多樣了:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import fs from 'fs'
import { default as fs } from 'fs'
import * as 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'

import 屬於靜態編譯,所以沒辦法動態加載,但 require 就可以了:

1
2
3
4
const url = "a" + "b"

import url // => 噴錯
require(url) //=> OK

雖然在 node.js v9 以上版本就可以使用 ES6 了,但是還是需要設定一些東西,避免麻煩,大家多半還是用 webpack + babel 解決。


本質上的不同

  1. CommonJS 還是 ES6 Module,輸出都可以看成是一個具備多個屬性或方法的對象。
  2. default 是 ES6 Module 所獨有的關鍵字,export default fs 輸出默認的對象,import fs from ‘fs’ 可以直接導入這個對象。
  3. ES6 Module 中導入模塊的屬性或方法是強綁定的,包括基礎類型;而 CommonJS 則是普通的值傳遞或是引用傳遞,舉個例子:
counter.js
1
2
3
4
exports.count = 0
setTimeout(function () {
  console.log('increase count to', ++exports.count, 'in counter.js after 500ms')
}, 500)
commonjs.js
1
2
3
4
const { count } = require('./counter')
setTimeout(function () {
  console.log('read count after 1000ms in commonjs is', count)
}, 1000)
es6.js
1
2
3
4
import { count } from './counter'
setTimeout(function () {
  console.log('read count after 1000ms in es6 is', count)
}, 1000)

以上,分別運行 common.js 與 es6.js:

1
2
3
4
5
6
7
node common.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

小結

效能的差異

ES6 的 import 是編譯中執行;CommonJS 的 require 是同步加載,import 無論在 node.js 或是瀏覽器都不能直接使用,透過 Babel 轉譯後還是使用 CommonJS 加載,所以兩者其實透過轉譯後是一樣的,只是遵循的規範及出現的時間點不同而已。

在效能上基本上沒區別,因為轉譯過後還是一樣的東西。

  • 基本上現在能用 ES6 寫 import 就用吧!
  • 有用 webpacker/babel 的話,不用在意 import 與 require 的效能,因為最後都會轉為 CommonJS。
  • 需要動態加載時才使用 require。

comments powered by Disqus