在前文的 what?why?之後就是我們最直接的如何實現我們的模組編譯器了。
在 nodejs 中其自帶的模組化方法require
是最常見的一種引入其他模組的方式。我們來簡單回顧一下 nodejs 中如何使用require
來引入其他模組。
實現功能需要兩個檔案:
cache
├── cache.js
└── index.js
/**
* cache/cache.js
*/class
cache;}
get(key)
set(key, value)
}module.exports =
newcache()
;// 匯出乙個例項化的 cache 物件。
/**
* cache/index.js
*/const cache =
require
('./cache');
// 匯入 cache 模組中例項化的 cache 物件。
cache.
set(
'name'
,'herb');
console.
log(cache.
get(
'name'))
;// herb
到現在為止都是使用了標準的 nodejs 模組函式require
。那麼如果僅僅是知道require
是怎麼用的其實只是滿足了乙個初級程式設計師的需求。那麼從想完成從初級->高階這一跨越,就至少要了解require
的機制,nodejs 如何通過require
來完成不同模組之間的引用的呢???
當我們遇到問題需要分析一些工具的底層原理的時候,往往會走兩條路:
閱讀工具的官方文件甚至原始碼
這兩條路沒有優劣之分,也不要糾結哪種方式更好。我認為這兩種方式是屬於不同層次的,第一種看別人理解後的內容是一條捷徑,往往是從更高抽象層次去理解其原理。第二種應該是建立在對原理有大致了解之後去細化的乙個過程。
這裡作者就不分析原始碼了,把require
最精華的部分梳理出來,幫助我們做出 mvp(minimum viable product)就可以。
如果我們仔細觀察現有的**,會注意到:
從上面幾個特徵可以得出其重要的兩個點:
從上面require
的原理中可以得出乙個模組module
有乙個重要屬性exports
,還有require
是根據檔案路徑尋找到這個模組的,最容易想到的是每個模組可以通過其檔案路徑唯一標識它。那麼乙個模組至少就擁有兩個屬性:
├── cache
│ ├── cache.js
│ └── index.js
├── module.js
/**
* module.js
*/class
module
)}
那麼這就解釋了在分析(
function
(exports, require, module, __filename, __dirname)
);
require
原理的時候的乙個疑惑,require
和module
的**問題。其實就是包裹模組的函式的兩個引數。
同樣的我們可以簡單實現最基礎的模組,只需要包裹模組的函式有兩個引數就足夠了require
和module
,為了更清晰的展示其工作原理,我們將cache.js
的檔案內容拷貝直接拷貝到module.js
中,幷包裹在乙個函式裡:
/**
* module.js
*/class
module)}
function
cache
(module, require);}
get(key)
set(key, value)
} module.exports =
newcache()
;// 匯出乙個例項化的 cache 物件。
}
那麼如何才能建立並匯出正確的cache
模組呢?
首先是先建立出我們的cachemodule
模組物件:
const cachemodule =
newmodule
('cache.js',)
;
此時我們給模組的id
暫時設為./cache
,並且exports
初始為乙個空物件{}
然後呼叫cache
方法來載入我們的模組,
在模組內部暫時並沒有使用require
方法,所以先忽略掉它:
cache
(cachemodule)
;
很顯然執行完cache
方法之後,我們的cachemodule
的exports
屬性就會包含我們匯出的new cache()
這一物件了:
console.
log(cachemodule)
;// module } }
到此我們完成了cachemodule
的建立工作。
同樣的我們以相同的方式包裹index.js
的檔案內容,然後載入我們的index.js
模組,唯一不同的是我們需要實現require
方法來引入cache.js
模組。
由於我們每個模組都有乙個唯一標識id
,那麼我們可以建立乙個modules
的物件來索引我們的模組:
const modules =
;
那麼根據require
函式的需求:
根據模組實現乙個簡單id
找到對應模組,並返回模組的匯出物件exports
require
函式:
const
__require__
=(id)
=> modules[id]
.exports;
// 避免與 nodejs 自身的 require 衝突。
包裹並載入我們的index.js
模組:
function
index
(module, require)
const indexmodule =
newmodule
('index.js');
index
(indexmodule, __require__)
;// herb
其實index.js
模組就是我們程式的入口檔案,載入入口檔案就等同於執行了我們的程式。此時我們通過執行node module.js
之後就能看到終端列印出了herb
。 第乙個nodejs應用
應用這個詞很火,都在用。這裡的nodejs應用其實是乙個站點,準確的說是執行在本地的乙個小小的http站點。但是nodejs開發主要還是集中在少數的幾個核心功能上,而不是那種動輒幾千幾萬個檔案,支撐多少併發多少功能的這種大型站點。所以nodejs開發的這些小型http站點也叫做應用。當然nodejs...
linux第乙個驅動模組編譯
我們的源程式是乙個簡單的程式 include include module license dual bsd gpl static int hello init void static void hello exit void module init hello init module exit h...
Nodejs的第乙個頁面
網上nodejs的文章已經很多,這裡只是寫下自己的小小心得,如果能幫到別人當然更好。安裝nodejs後啟動node.js,會開啟乙個類似黑色的系統命令框,這裡是直接輸入js 的命令框,因此在這裡輸入 node v 會提示你沒有node 這個命令,如 如果你想安裝其他的包,如 express 等,就需...