天天看點

import和require差別

遵循的子產品化規範不一樣

子產品化規範:即為 JavaScript 提供一種子產品編寫、子產品依賴和子產品運作的方案。誰讓最初的 JavaScript 是那麼的裸奔呢——全局變量就是它的子產品化規範。

require/exports 出生在野生規範當中,什麼叫做野生規範?即這些規範是 JavaScript 社群中的開發者自己草拟的規則,得到了大家的承認或者廣泛的應用。比如 CommonJS、AMD、CMD 等等。import/export 則是名門正派。TC39 制定的新的 ECMAScript 版本,即 ES6(ES2015)中包含進來。

出現的時間不同

require/exports 相關的規範由于野生性質,在 2010 年前後出生。AMD、CMD 相對命比較短,到 2014 年基本上就搖搖欲墜了。一開始大家還比較喜歡在浏覽器上采用這種異步小子產品的加載方式,但并不是銀彈。随着 Node.js 流行和 Browsersify 的興起,運作時異步加載逐漸被建構時子產品合并分塊所替代。Wrapper 函數再也不需要了。 2014 年 Webpack 還是新玩意,現在已經是前端必備神器了。

Browsersify、Webpack 一開始的目的就是打包 CommonJS 子產品。

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 和 import/export 形式不一樣

require/exports 的用法隻有以下三種簡單的寫法:

const fs = require('fs')
exports.fs = fs
module.exports = fs      

而 import/export 的寫法就多種多樣:

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'      

require/exports 和 import/export 本質上的差别

  1. CommonJS 還是 ES6 Module 輸出都可以看成是一個具備多個屬性或者方法的對象;
  2. default 是 ES6 Module 所獨有的關鍵字,export default fs 輸出預設的接口對象,import fs from ‘fs’ 可直接導入這個對象;
  3. ES6 Module 中導入子產品的屬性或者方法是強綁定的,包括基礎類型;而 CommonJS 則是普通的值傳遞或者引用傳遞。1、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)      
➜  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      

繼續閱讀