CommonJS淺析

規範地址 http://www.commonjs.org/
nodejs modules文檔地址 http://nodejs.cn/api/modules....html

核心邏輯

在執行模塊代碼以前,nodejs會使用一個閉包(The module wrapper)封裝起來,這就是它每個文件都是一個獨立的域的緣由。但若是值沒有用var聲明的變量,會直接提高到全局上去,在其餘文件也能夠直接使用。node

nodejs會經過下面一個閉包把文件給包起來api

(function(exports, require, module, __filename, __dirname) {
// 模塊的代碼實際上在這裏
});

咱們可使用閉包

console.log(JSON.stringify(arguments))
能夠看到當前js文件封裝以後的參數
例:
aa.js
console.log(JSON.stringify(arguments))
//  {"0":{},"2":{"id":".","exports":{},"parent":null,"filename":"D:\\code\\js\\aa.js","loaded":false,"children":[],"paths":["D:\\code\\js\\node_modules","D:\\code\\node_modules","D:\\node_modules"]},"3":"D:\\code\\js\\aa.js","4":"D:\\code\\js"}‘

能夠看到這裏返回的對象對應着exports, require, module, __filename, __dirnameapp

exports

在整個域裏,會有兩個exports,一個模塊封裝器裏的首個參數,一個是module類裏的。
兩個exports引用了同一塊堆內存,require引用時實際上拿的是module類裏的ui

require

用於引入模塊、 JSON、或本地文件。 能夠從 node_modules 引入模塊。 可使用相對路徑(例如 ./、 ./foo、 ./bar/baz、 ../foo)引入本地模塊或 JSON 文件,路徑會根據 __dirname 定義的目錄名或當前工做目錄進行處理。code

上面是官網對require的定義,require的一些屬性使用在官網也有定義htm

module

在每一個模塊中, module 的自由變量是對錶示當前模塊的對象的引用。 爲方便起見,還能夠經過全局模塊的 exports 訪問 module.exports。 module 實際上不是全局的,而是每一個模塊本地的。對象

__filename

當前模塊的文件名。 這是當前的模塊文件的絕對路徑(符號連接會被解析)。內存

__dirname

當前模塊的目錄名。 與 __filename 的 path.dirname() 相同。

特殊使用

循環引用

當循環調用 require() 時,一個模塊可能在未完成執行時被返回。

例如如下狀況:

a.js:

console.log('a 開始');
exports.done = false;
const b = require('./b.js');
console.log('在 a 中,b.done = %j', b.done);
exports.done = true;
console.log('a 結束');
b.js:

console.log('b 開始');
exports.done = false;
const a = require('./a.js');
console.log('在 b 中,a.done = %j', a.done);
exports.done = true;
console.log('b 結束');
main.js:

console.log('main 開始');
const a = require('./a.js');
const b = require('./b.js');
console.log('在 main 中,a.done=%j,b.done=%j', a.done, b.done);

當 main.js 加載 a.js 時, a.js 又加載 b.js。 此時, b.js 會嘗試去加載 a.js。 爲了防止無限的循環,會返回一個 a.js 的 exports 對象的 未完成的副本 給 b.js 模塊。 而後 b.js 完成加載,並將 exports 對象提供給 a.js 模塊。

當 main.js 加載這兩個模塊時,它們都已經完成加載。 所以,該程序的輸出會是:

$ node main.js
main 開始
a 開始
b 開始
在 b 中,a.done = false
b 結束
在 a 中,b.done = true
a 結束
在 main 中,a.done=true,b.done=true
相關文章
相關標籤/搜索