node、es6的module使用對比exports、require、import

node和es6中的模塊使用對比

目前使用js變成離不開模塊,而如今最爲常見的模塊也就是node採用的COMMONjs的方式和es6規範,這裏對兩種的使用進行對比,並無深刻源碼盡情扣,html

node--commonjs規範的模塊化

node的模塊是比較常見的,是全局變量global中的一個屬性,文件和模塊是一一對應的(每一個文件被視爲一個獨立的模塊)。node

使用

目前比較規範的是一個文件就是一個模塊,主要是exports和require進行處理,react

exports

exports 變量是在模塊的文件級別做用域內有效的,它在模塊被執行前被賦於 module.exports 的值。它有一個快捷方式,以便 module.exports.f = ... 能夠被更簡潔地寫成 exports.f = ...。 注意,就像任何變量,若是一個新的值被賦值給 exports,它就再也不綁定到 module.exports。能夠具體看看代碼:es6

function add(x, y){
    return x+y;
}
function multiply(x, y){
    return x*y;
}
exports.add = (x, y) => x+y; //exports做爲module.exports的快捷方式
exports.multiply = (x, y) => x*y;
module.exports = add; //此時exports module.exports重新被賦爲新對象或者函數(函數也是對象)
exports = {add: add} //這是exports已經和module.exports沒有關係了,成了獨立的模塊做用域內對象,並不會被導出
module.exports = {  //最後的導出部分
        add: add,
        multiply: multiply
    };

關於exports和module.exports的關係看下面代碼的相似實現,好像實參和形參同樣,不一樣的是最後若是module.exports的沒有直接複製操做,會被賦值爲exports。express

function require(/* ... */) {
  const module = { exports: {} };
  ((module, exports) => {
    // 模塊代碼在這。在這個例子中,定義了一個函數。
    function someFunc() {}
    exports = someFunc;
    // 此時,exports 再也不是一個 module.exports 的快捷方式,
    // 且這個模塊依然導出一個空的默認對象。
    module.exports = someFunc;
    // 此時,該模塊導出 someFunc,而不是默認對象。
  })(module, module.exports);
  return module.exports;
}

require

定義好了一個模塊就應該使用它,編程

var test = require('./moduleTest.js');

console.log(test(1, 2));
console.log(mutiply(1, 2));

使用是比較簡單的,使用變量獲取導出的對象exports,就可使用對象裏面的方法了,咱們有的時候可能會遇到這樣的狀況,無需使用變量接受模塊的exports,既能夠直接使用,這種狀況通常是在模塊代碼導出的時候作了處理:api

module.exports.add = global.add = (x, y) => x+y;

把模塊的方法直接提高到全局做用域,這其實並非好的選擇。緩存

module對象的一些解讀

Node 使用兩個核心模塊來管理模塊依賴:模塊化

  1. require 模塊,是個看起來像在全局做用域有效的模塊——不須要 require('require')。函數

  2. module 模塊,看起來也像是在全局做用域內有效——不須要 require('module')。

由 require 模塊導出的主要對象是一個函數(如上例所用)。 當 Node 使用本地文件路徑做爲函數的惟一參數調用該 require() 函數時,Node 將執行如下步驟:

  • 解析:找到文件的絕對路徑。

  • 加載:肯定文件內容的類型.

  • 封裝:給文件其私有做用域。 這使得 require 和 module 對象二者均可如下載咱們須要的每一個文件。

  • 評估:這是 VM 對加載的代碼最後須要作的。

  • 緩存:當咱們再次須要這個文件時,再也不重複全部的步驟。

模塊在第一次加載後會被緩存。 這也意味着(相似其餘緩存機制)若是每次調用 require('foo') 都解析到同一文件,則返回相同的對象。

屢次調用 require(foo) 不會致使模塊的代碼被執行屢次。 這是一個重要的特性。 藉助它, 能夠返回「部分完成」的對象,從而容許加載傳遞的依賴, 即便它們會致使循環。

模塊是基於其解析的文件名進行緩存的。 因爲調用模塊的位置的不一樣,模塊可能被解析成不一樣的文件名(好比從 node_modules 目錄加載),這樣就不能保證 require('foo') 總能返回徹底相同的對象。

此外,在不區分大小寫的文件系統或操做系統中,被解析成不一樣的文件名能夠指向同一文件,但緩存仍然會將它們視爲不一樣的模塊,並屢次從新加載。 例如,require('./foo') 和 require('./FOO') 返回兩個不一樣的對象,而不會管 ./foo 和 ./FOO 是不是相同的文件。

es6的模塊

在ES6以前,要使用一個模塊,必須使用require函數將一個模塊引入,但ES6並無採用這種模塊化方案,在ES6中使用import指令引入一個模塊或模塊中的部分接口,並無將require寫入標準,這也就是說require對於ES6代碼而言,只是一個普通函數。

同理,在ES6標準中,導出模塊的接口也只能使用export指令,而非exports對象,這也一樣意味着module.exports只是node,requirejs等模塊化庫的自定義變量,而非ES標準接口。

固然,ES6的模塊化也很複雜,不僅模塊接口的導入導出這點東西,只不過本文無恥的只討論這個相對而言比較常見的問題。

export使用

先列舉一些經常使用的使用方法:

export function fun() {};
export { name1, name2, …, nameN };
export { variable1 as name1, variable2 as name2, …, nameN };
export let name1, name2, …, nameN; // also var
export let name1 = …, name2 = …, …, nameN; // also var, const

export default expression;
export default function (…) { … } // also class, function*
export default function name1(…) { … } // also class, function*
export { name1 as default, … };

export * from …;
export { name1, name2, …, nameN } from …;
export { import1 as name1, import2 as name2, …, nameN } from …;

導出的不是變量是絕對錯誤的,包括導出表達式,也是絕對錯誤的,export容許屢次export {}這種形式,看上去很奇怪,其實和react的setState同樣,是一個增量的添加模式。另外,ES6更厲害之處在於,能夠在export變量以後,繼續修改變量。

import使用

import的使用其實比require更加的舒服

import {a,obj} from './module-file';

和node以前的require不同,require只能把模塊放到一個變量中,而在ES6中,擁有對象解構賦值的能力,因此直接就把引入的模塊的接口賦值給變量了。內在機理也有不一樣,require須要去執行整個模塊,將整個模塊放到內存中(也就是咱們說的運行時),若是隻是使用到其中一個方法,性能上就差不少,而import...from則是隻加載須要的接口方法,其餘方法在程序啓動以後根本觸及不到,因此這種又被稱爲「編譯時」,性能上好不少。

AS DEFAULT * 關鍵字

編程的同窗對as都容易理解,簡單的說就是取一個別名。上面export中能夠用,import中其實也能夠用:

// a.js
var a = function() {};
export {a as fun};

// b.js
import {fun as a} from './a';
a();

而default則是一種語法糖,實踐相似:

// d.js
export default function() {}

// 等效於:
function a() {};
export {a as default};

//在import的時候,能夠這樣用:
import a from './d';

// 等效於,或者說就是下面這種寫法的簡寫,是同一個意思
import {default as a} from './d';

則是表明把全部的export賦值給 as newExport,這個後面跟這個的別名對象,從而獲取模塊全部方法。

參考:http://www.tangshuang.net/288...
https://juejin.im/entry/58d4e...
http://nodejs.cn/api/modules....

相關文章
相關標籤/搜索