模塊化規範:即爲 JavaScript 提供一種模塊編寫、模塊依賴和模塊運行的方案。誰讓最初的 JavaScript 是那麼的裸奔呢 —— 全局變量就是它的模塊化規範。前端
require/exports 出生在野生規範當中,什麼叫作野生規範?即這些規範是 JavaScript 社區中的開發者本身草擬的規則,獲得了你們的認可或者普遍的應用。好比 CommonJS、AMD、CMD 等等。import/export 則是名門正派。TC39 制定的新的 ECMAScript 版本,即 ES6(ES2015)中包含進來。node
require/exports 相關的規範因爲野生性質,在 2010 年先後出生。AMD、CMD 相對命比較短,到 2014 年基本上就風雨飄搖了。一開始你們還比較喜歡在瀏覽器上採用這種異步小模塊的加載方式,但並非銀彈。隨着 Node.js 流行和 Browsersify 的興起,運行時異步加載逐漸被構建時模塊合併分塊所替代。Wrapper 函數不再須要了。 2014 年 Webpack 仍是新玩意,如今已是前端必備神器了。es6
Browsersify、Webpack 一開始的目的就是打包 CommonJS 模塊。npm
CommonJS 做爲 Node.js 的規範,一直沿用至今。因爲 npm 上 CommonJS 的類庫衆多,以及 CommonJS 和 ES6 之間的差別,Node.js 沒法直接兼容 ES6。因此現階段 require/exports 仍然是必要的。出自 ES6 的 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 的用法只有如下三種簡單的寫法:babel
const fs = require('fs') exports.fs = fs module.exports = fs
而 import/export 的寫法就多種多樣:app
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'
形式上看起來五花八門,但本質上:異步
一、2 相對比較好理解,3 須要看個例子:模塊化
// counter.js exports.count = 0 setTimeout(function () { console.log('increase count to', exports.count++, 'in counter.js after 500ms') }, 500) // commonjs.js const {count} = require('./counter') setTimeout(function () { console.log('read count after 1000ms in commonjs is', count) }, 1000) //es6.js import {count} from './counter' setTimeout(function () { console.log('read count after 1000ms in es6 is', count) }, 1000)
分別運行 commonjs.js 和 es6.js:
➜ test node commonjs.js increase count to 1 in counter.js after 500ms read count after 1000ms in commonjs is 0 ➜ test babel-node es6.js increase count to 1 in counter.js after 500ms read count after 1000ms in es6 is 1
ES6模塊的設計思想,是儘可能的靜態化,使得編譯時
就能肯定模塊的依賴關係(「靜態優化」),以及輸入和輸出的變量。CommonJS和AMD模塊,都只能在運行時
肯定這些東西(「運行時加載」)。
ES6模塊不是對象,而是經過export命令顯式指定輸出的代碼,輸入時也採用靜態命令的形式。
CommonJS和AMD模塊是一個對象。
ES6模塊加載的機制,與CommonJS模塊徹底不一樣。CommonJS模塊輸出的是一個值的拷貝,而ES6模塊輸出的是值的引用。
CommonJS模塊輸出的是被輸出值的拷貝,也就是說,一旦輸出一個值,模塊內部的變化就影響不到這個值。ES6模塊是動態引用,而且不會緩存值,模塊裏面的變量綁定其所在的模塊。
處理「循環加載」的方法是不同的,返回的結果也不同。
CommonJS模塊的重要特性是加載時執行,即腳本代碼在require的時候,就會所有執行。一旦出現某個模塊被"循環加載",就只輸出已經執行的部分,還未執行的部分不會輸出。
ES6模塊是動態引用,若是使用import
從一個模塊加載變量,那些變量不會被緩存,而是成爲一個指向被加載模塊的引用,須要開發者本身保證,真正取值的時候可以取到值。