你的第乙個 Nodejs 模組編譯器 2

2021-09-26 06:59:49 字數 3956 閱讀 5264

在前文的 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原理的時候的乙個疑惑,requiremodule的**問題。其實就是包裹模組的函式的兩個引數。

同樣的我們可以簡單實現最基礎的模組,只需要包裹模組的函式有兩個引數就足夠了requiremodule,為了更清晰的展示其工作原理,我們將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方法之後,我們的cachemoduleexports屬性就會包含我們匯出的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 等,就需...