全局內容是有點相似於咱們在瀏覽器編程的時候的window對象的,當時在node之中雖然咱們編寫的變量會自動的給出上下文環境(模塊),可是全局變量的存在仍是大大的幫助了咱們編程時候的便捷性。咱們能夠在任意的模塊之中使用全局環境下面定義的內容。node
global其實就至關於在web編寫線面的window內容。是爲nodeJS中的全局變量內容。其中存儲的內容包括,console的全局實例,process信息內容,定時函數內容,Buffer對象內容等,固然還有一些特殊信息的變量。下面咱們一一來講明。web
## 首先咱們來看一看其中連個特殊的全局變量,__dirname和__filename。咱們先來上一段代碼吧。npm
-----------------mod.js-----------------
console.log('mod.js的filename:'+ __filename);
console.log('mod.js的dirname:'+ __dirname);
-----------------main.js-----------------
require('./mod.js');
當咱們運行main.js的時候nodeJS會自動的先將mod.js的內容運行一遍,而後咱們就能夠在控制檯看到打印出來的信息了。編程
固然二者之間仍是有些差異的,__dirname 的值其實至關於path.dirname(__filename),__filename展現的是文件的局對路徑包括文件名稱。而__dirname展現的是文件所在的文件夾的路徑信息。json
## 接下來咱們聊一聊require,module,exports的部分。瀏覽器
相信只要稍寫過nodeJS的人都知道這3個次。require方法來請求模塊,module表示當前文件模塊自己,exports內容表示的是模塊對外接口部分。緩存
require內容用於咱們請求相關模塊內容,當咱們傳入了文件的相對路徑給require方法以後,咱們將獲得一個引入模塊的對象。可是咱們經常使用npm來下載項目支持的模塊文件,這是咱們經常只須要輸入模塊名稱以後reqiure會自動的引入相關的內容。這是由於在工程文件之下,在node_modules文件夾之中,咱們用模塊名稱命名的文件夾,require會一句模塊名稱到相應的文件夾之中找到默認的index.js文件來進行引入。固然也是能夠修更名稱的,只是這時咱們須要運用到package.json文件來描述這一模塊內容的信息,這樣咱們能夠指定進入模塊的文件。固然require在引入了某一個文件以此以後再次引入的時候實際上是無需再次讀取文件的,由於require之中有緩存機制內容,以後再次請求的時候實際上是直接從對應的內存之中獲取。在0.3的版本以後require之中添加了require.cache對象以鍵值對的形式存儲,固然咱們能經過鍵值key的部分來進行緩存內容的刪除,那麼下一次再加載的時候則模塊會從新加載。咱們;愛看一段代碼吧:函數
var ser = require('./src/h_server.js');
var buf = require('./src/h_buffer.js');
console.log(require.cache); //引入當前的兩個外界模塊,打印相關的require.cache內容
結果以下:學習
這裏我截取的是其中一段內容,一個對象屬性,能夠看到,齊以文件路徑內容爲變量名稱,以module內容座位屬性來進行存儲,因此咱們要刪除檔當前對象中的內容的狀況只須要經過文件路徑查找到module對象並刪除就好。ui
P.S.:包管理器內容(nodeJS文檔中與module模塊文檔下的附加內容)
這裏詳細說一下包引入與管理,當咱們在某一文檔下建立本身的node工程的時候,咱們經常須要外部引入許多的模塊內容,這是咱們經過NPM來下載模塊的時候回發現工程目錄之下會多出一個文件夾名稱爲node_module,併爲每個下載的外鏈模塊有一個單獨的文件夾內容。這時候咱們能夠經過模塊名稱來直接引用相關的模塊內容,這是由於包管理器,當咱們內容引入的時候會聽從必定的規則內容,這裏我引用一張官網的總結內容。
從 Y 路徑的模塊 require(X)
1. 若是 X 是一個核心模塊,
a. 返回核心模塊
b. 結束
2. 若是 X 是以 '/' 開頭
a. 設 Y 爲文件系統根目錄
3. 若是 X 是以 './' 或 '/' 或 '../' 開頭
a. 加載文件(Y + X)
b. 加載目錄(Y + X)
4. 加載Node模塊(X, dirname(Y))
5. 拋出 "未找到"
加載文件(X)
1. 若是 X 是一個文件,加載 X 做爲 JavaScript 文本。結束
2. 若是 X.js 是一個文件,加載 X.js 做爲 JavaScript 文本。結束
3. 若是 X.json 是一個文件,解析 X.json 成一個 JavaScript 對象。結束
4. 若是 X.node 是一個文件,加載 X.node 做爲二進制插件。結束
加載索引(X)
1. 若是 X/index.js 是一個文件,加載 X/index.js 做爲 JavaScript 文本。結束
3. 若是 X/index.json 是一個文件,解析 X/index.json 成一個 JavaScript 對象。結束
4. 若是 X/index.node 是一個文件,加載 X/index.node 做爲二進制插件。結束
加載目錄(X)
1. 若是 X/package.json 是一個文件,
a. 解析 X/package.json,查找 "main" 字段
b. let M = X + (json main 字段)
c. 加載文件(M)
d. 加載索引(M)
2. 加載索引(X)
加載Node模塊(X, START)
1. let DIRS=NODE_MODULES_PATHS(START)
2. for each DIR in DIRS:
a. 加載文件(DIR/X)
b. 加載目錄(DIR/X)
NODE_MODULES_PATHS(START)
1. let PARTS = path split(START)
2. let I = count of PARTS - 1
3. let DIRS = []
4. while I >= 0,
a. if PARTS[I] = "node_modules" CONTINUE
b. DIR = path join(PARTS[0 .. I] + "node_modules")
c. DIRS = DIRS + DIR
d. let I = I - 1
5. return DIRS
固然,在咱們加載模塊的時候,當兩個相同的模塊放在不同的位置的時候加載的時候可能會重複加載並存儲兩個分加載以後的模塊對象,由於齊路徑的不相同,因此可能nodeJS沒法進行比對。
當讓在咱們引入的模塊的時候有的時候會遇到循環引入的狀況。這時node極可能會返回一個沒有執行完成的模塊對象內容來。
## module內容爲模塊,在咱們編寫每個JS文件的時候,node都認爲他是一個模塊,而module對象是表明當前編寫的這一模塊的信息。
module模塊是nodeJS的重要的組成部分,以前戳到nodeJS是以COMMONJS的規則來進行編寫的,而module着能夠說是組成這一規則的核心內容了。
因爲NODEJS會將每個文件當作一個模塊,因此經過node來進入的模塊其實是咱們的主體邏輯模塊內容,因此咱們又是須要判別當前運行模塊是否爲主模塊,這時咱們能夠經過require.main屬性來確認。module模塊之中會存儲文件入口路徑,咱們能夠經過module中的filename屬性來獲取,其值與在模塊之中調用__filename獲取的值多數狀況之下是相同的。固然咱們若是想要獲取住模塊的入口路徑咱們也能夠經過,require.main.filename來獲取,因而可知require中的main屬性存儲的其實是組模塊對象。
下面說一下模塊的包管理器,其原理其實是將模塊放入到一個自執行函數之中,這樣的好處顯而易見了,首先是能夠隔絕當前的模塊與全局環境,以避免全局環境被污染,同時這樣爲模塊肯定獨立的上下文使得每個模塊之間的上下文不相互干擾,當某一模塊之中與另外一模塊之中存在相同名稱的命名的時候不會出現衝突的狀況,nodeJS的實現方式以下:
(function(exports, require, module, __filename, __dirname) {
// 模塊的代碼實際上在這裏
});
接下來咱們來看一看module對象之中的某些屬性內容:
-- children:這個屬性展現的是一個列表內容,其中存儲的是當前模塊引用的模塊對象。
-- parent:這個屬性則存儲的是引用當前模塊對象的模塊對象。
-- loaded:這個屬性代表的是當前的模塊是否已經加載完成了。
-- path:這個屬性存儲的是模塊的搜索路徑。
-- filename:這個屬性內容存儲的是模塊的徹底解析後的文件名。
-- id: 模塊的標識符。 一般是徹底解析後的文件名。
-- exports:這個屬性是重中之重,屬性中存儲的是當前模塊的公用方法內容,當使用require來引入模塊的時候,實際上就是經過這屬性來確立的,exports能夠理解爲模塊暴露在大衆視線下面的接口。固然咱們也能說得更爲的概念化一點,官方文檔是如是說的—— exports變量是在模塊的文件級別做用域內有效的,它在模塊被執行前被賦予 module.exports 的值。
## exports屬性是一個文件級別做用域有效的屬性,以前在module之中有提到這一屬性,可是module.exports這一屬性和單獨的exports仍是有些不相同的因此纔會將這一屬性單獨拿出來講事。exports屬性只要是編寫的朋友都知道,經過它其實也是能夠對module.exports這一屬性進行相關的賦值的。例如,當咱們對某一文件下面使用exports對象屬性賦予a屬性,並對a賦值爲‘1’,如展現
exports.a = '1';
這時候nodeJS會自動的將其內容複製給module.exports屬性之中。當module.exports指向的對象沒有變而只是變化對象內容的時候,則exports指向的對象其實也是會變的。代碼以下:
console.log(module.exports); //展現最初的module.exports屬性中的內容
console.log('_______________________________');
//改變exports的值,看module.exports內容會如何變化。
exports.main = 'main.js';
console.log('exports:');
console.dir(exports);
console.log('module.exports:');
console.dir(module.exports);
console.log('_______________________________');
//改變module.exports的值看exports會如何變化
module.exports.checkData = 'checkData';
console.log('exports:');
console.dir(exports);
console.log('module.exports:');
console.dir(module.exports);
console.log('_______________________________');
//改變module.exports指向的對象,看exports的變化。
module.exports = {
main:'afterChange'
}
console.log('exports:');
console.dir(exports);
console.log('module.exports:');
console.dir(module.exports);
console.log('_______________________________');
//再次改變exports的值,看module.exports怎樣變化。
exports.checkAgain = 'checkAgain';
console.log('exports:');
console.dir(exports);
console.log('module.exports:');
console.dir(module.exports);
console.log('_______________________________');
相應結果內容:
由上面能夠知道,在咱們編寫模塊的時候初始狀況下exports和module.exports是指向同一個對象的,因此exports在改變的時候module.exports也會跟着改變,而當module.exports改變其指向的obj以後咱們能夠發現其之間的變化不相關了。因此咱們其實能夠這樣理解,當初始化的是時候的全局的exports屬性和module.exports是指向同一個空的obj的。而當改變了其中一個屬性的指向的時候則兩個變量將不會再有任何關係。
##定時函數內容的學習。
咱們在編寫JS的時候常常會使用到定時函數等內容,來延時執行或者是循環執行某一段邏輯內容固然nodeJS之中也是有相對應的函數的,其中主要的有3個形式的函數內容。分別是setInterval,setTimeout,setImmediate。前兩個函數內容就不用多說了,寫過JS的都知道,第三個函數的做用是當前事件循環結束的時候立馬執行(事件循環以後會有說)。
下面咱們來了解一下timeout類,這是nodeJS中的一個定時器對象,setTimeout和setInterval對象執行的時候其返回的內容在nodeJS中是一個定時器對象。當定時器對象是活動的狀態的時候,則事件循環就會將其添加到的檔次循環待執行列表之中。固然nodeJS爲咱們添加了兩個設置timeout對象活動狀態的函數,ref()使得定時器對象處於活動狀態,unref()使得當前定時器函數處於非活動狀態。