本文同步自我的個人博客:http://www.52cik.com/2015/12/14/learn-node-modules-module.html
上一篇講了模塊是如何被尋找到然后加載進來的,這篇則是如何導出屬性方法以及自定義模塊后綴等一系列模塊問題。
exports 對象
這是最常見的對象了,以往導出都是這樣寫的。
// a.js
exports.bar = '屬性';
exports.fn = function () { return '方法' };
// b.js
var a = require('./a');
console.log(a.bar); // 屬性
console.log(a.fn()); // 方法
一直都是這么用非常簡單,但是不能直接用對象覆蓋他,如下代碼是不對的。
// a.js
exports = {
bar: '屬性',
fn: function () { return '方法' }
};
// b.js
var a = require('./a');
console.log(a.bar); // undefined
console.log(a.fn()); // 報錯
為什么不能直接覆蓋呢,因為 exports
只是 module.exports
對象的引用。
module.exports
對象
如果要導出一整個對象或者構造函數之類的,就需要用到 module.exports
對象了。
// a.js
module.exports = {
bar: '屬性',
fn: function () { return '方法' }
};
// b.js
var a = require('./a');
console.log(a.bar); // 屬性
console.log(a.fn()); // 方法
導出構造函數:
// klass.js
function klass () {}
klass.prototype.say = function () { return '我是klass' };
module.exports = klass;
// b.js
var Klass = require('./klass');
var klass = new Klass();
console.log(klass.say()); // 我是klass
module 其他屬性
module 還有些其他屬性,簡單說下吧。
module.id
模塊id,往往是模塊路徑module.children
子模塊module.filename
模塊路徑module.loaded
是否加載完畢module.parent
父模塊module.paths
各級 node_modules 目錄路徑
require 函數
說模塊,當然離不開 require
函數,除了加載模塊之外,他還有一些其他用法。
require.resolve
不會加載執行,只會返回模塊的絕對路徑。require.cache
緩存所有已經加載的模塊,如果你要更新模塊就要刪除這里的緩存。
var a = require('./a');
var p = require.resolve('./a'); // 得到模塊路徑
delete require.cache[p]; // 刪除模塊緩存
雖然不清楚什么時候用,但是至少是這么用的,刪除緩存后,下次加載這個模塊,就會重新加載模塊文件了。
require.extensions
自定義模塊后綴
還有個 require.extensions
非常好用的屬性,但遺憾的是官方提示棄用了這個屬性,不過值得慶幸的是,這個屬性永遠不會被移除,只是不推薦使用而已。
我第一次注意到這個屬性是在 ejs 源碼里,當時很好奇這是個什么東西,去翻了下官方文檔,發現撿到寶了。后來又發現 node 命令行下的 babel 模塊也注冊了自定義模塊,后綴分別是 .es
, .es6
, .jsx
,可以直接 require('./a.es6')
或者是 require('./a.jsx')
得到編譯好的 js 代碼。
好了,不說廢話了,來看個官方簡單例子吧。
require.extensions['.json'] = function(module, filename) {
var content = fs.readFileSync(filename, 'utf8');
try {
module.exports = JSON.parse(content);
} catch (err) {
err.message = filename + ': ' + err.message;
throw err;
}
};
這是 node 源碼的 json 模塊實現,我只是刪除了一個 stripBOM 函數,為了方便大家理解。
當然官方不推薦這樣做是有道理的,官方推薦編譯為兼容的 js 代碼模塊運行,性能更佳,而不應該采用這樣的自定義模塊實現。
不過看用途而定了,有時候也不一定追求極致的性能。