JavaScript 的 module 直到 ES6 才支援,所以 JavaScript 非原生的模組非常盛行,其中比較有名的是 AMD
跟 CommonJS
。node 本身使用的就是 CommonJS
的模組規範。
module
跟 exports
是兩個模組載入時會丟入環境的變數。
module 除了有 id
、filename
、loaded
、parent
、children
等等屬性,初學最重要的是他的 exports
屬性,module.exports
的值就會是模組輸出的東西。
下面是一些基本的用法:
module.exports = 1;
module.exports = 'a module';
module.exports = function() {
};
module.exports = {
a: 'test',
myMethod: function() {
}
};
module.exports = Car;
function Car() {
}
這個變數是整個環節最難理解的一部分,其實 exports
就是一個指向 module.exports
的參考。也就是說用 exports 可以直接在 module 下面綁上屬性或方法
下面這個範例達到跟上面輸出物件的範例會有一樣效果:
exports.a = 'test';
exports.myMethod = function() {
};
千萬不要把任何值直接 assign 到 exports:
exports = function() {};
這裡需要一點指標跟參考的概念,如果 exports 直接被指定了其他的值,他就失去了對 module.exports 的參考,所以 exports 就失去了意義,也無法繼續把屬性跟方法綁到模組上。
下面是官方文件的一個假想實作:
function require(...) {
// ...
function (module, exports) {
// Your module code here
exports = some_func; // re-assigns exports, exports is no longer
// a shortcut, and nothing is exported.
module.exports = some_func; // makes your module export 0
} (module, module.exports);
return module;
}
可以想像是在你的模組程式碼前跑了這樣一行:
var exports = module.exports;
再往下就會知道 module.exports 的參考不見了:
exports = function() {};
exports = module.exports = createApplication;
function createApplication() {
//...省略
}
exports.application = application;
exports.request = req;
exports.response = res;
以上程式碼節錄自 express
專案,使用 function 當作回傳值,並把數個值綁定到屬性下面。
所以可以直接當 function 使用,也可以使用模組下面的屬性:
var express = require('express');
var app = express();
var Router = express.Router;
以下則是來自 co
專案:
module.exports = co['default'] = co.co = co;
co.wrap = function (fn) { //... };
設定 default
跟 co
屬性都等於 module 自己,再接著添加方法。
載入模組的方式是使用 require 方法。
var http = require('http')
var myFn = require('./myFunction');
node 提供許多 C++ 撰寫的模組,例如:檔案系統 - fs
、HTTP 協定 - http
、加密 - crypto
,等等。
只要直接用關鍵字去載入即可:
var http = require('http');
var fs = require('fs');
使用 ./
或是 ../
開頭的,都會直接被當作是相對路徑,例如:
var app = require('./app');
var utils = require('../lib/utils');
如此可以直接拿到該檔案輸出的值。
使用 npm 安裝模組後,node_modules
目錄裡面就會出現相關的目錄:
npm install express
接著就可以直接在程式碼裡面載入:
var express = require('express');
第三方模組也像原生模組一樣,是使用關鍵字,所以 npm 上面的模組名稱不能重複註冊。
在使用相對路徑載入模組時,會依照下列順序尋找:
- .js
- .json
- .node
找不到 .js
時會尋找 .json
,最後才是 .node
檔。
載入第三方模組時,會先在該目錄下搜尋 node_modules
目錄裡有沒有那個模組的目錄,如果沒有就來到上層目錄繼續尋找 node_modules
,直到找到 global 安裝的資料夾都還找不到,則 throw exception。
模組只要載入一次,就會被快取。之後就會快很多。
node 模組跟 npm 密不可分,之後再寫一篇介紹 npm。