UMD 是 JavaScript 模塊的通用模塊定義模式。這些模塊能夠在任何地方工作,無論是在客戶端、服務(wù)器還是其他地方。
UMD 模式通常試圖提供與當(dāng)今最流行的腳本加載器(例如 RequireJS 等)的兼容性。 在許多情況下,它使用 AMD 作為基礎(chǔ),并添加了特殊的外殼來處理 CommonJS 兼容性。
所以首先要了解 AMD.
AMD 代表異步模塊定義(Asynchronous Module Definition). 它是 CommonJS (CJS) 規(guī)范的替代品。
API 指定了一種定義模塊的機(jī)制,以便可以異步加載模塊及其依賴項(xiàng)。 這特別適用于模塊的同步加載會(huì)導(dǎo)致性能、可用性、調(diào)試和跨域訪問問題的瀏覽器環(huán)境。
AMD 庫公開了一個(gè)全局定義函數(shù),其 footprint 為:
define(modulename?,[dependencyA?, dependencyB?, …], function (objectA, objectB, …) { ... var myExportedObj = function() { … } return myExportedObj; });
CommonJS 是一個(gè)項(xiàng)目,其目標(biāo)是為瀏覽器之外的 JavaScript 指定一個(gè)生態(tài)系統(tǒng)(例如,在服務(wù)器上或本地桌面應(yīng)用程序)。
服務(wù)器端 JavaScript 已經(jīng)存在很長時(shí)間了,并且可能提供一些與其他語言相比獨(dú)特而有趣的優(yōu)勢,因?yàn)榭蛻舳撕头?wù)器都使用相同的語言。
不幸的是,服務(wù)器端 JavaScript 非常分散。訪問文件的腳本在 rhino 和 V8 上未經(jīng)修改就無法使用。 Spidermonkey 和 JavaScriptCore 不能以相同的方式加載附加模塊。 JavaScript Web 框架與其解釋器密切相關(guān),并且經(jīng)常被迫創(chuàng)建一堆 Python、Ruby 和 Java 程序員認(rèn)為理所當(dāng)然的 API。
該項(xiàng)目的目標(biāo)是創(chuàng)建一個(gè)標(biāo)準(zhǔn)庫,最終允許 Web 開發(fā)人員在任意數(shù)量的 Web 框架和工具中進(jìn)行選擇,并在最適合其應(yīng)用程序的平臺(tái)上運(yùn)行該代碼。
例如, foo.js 在同一目錄中加載模塊 circle.js。
const circle = require('./circle.js'); console.log(`The area of a circle of radius 4 is ${circle.area(4)}`);
circle.js:
const PI = Math.PI; exports.area = function (r) { return PI * r * r; }; exports.circumference = function (r) { return 2 * PI * r; };
模塊 circle.js 已經(jīng)導(dǎo)出了函數(shù) area(..) 和 circle(..)。 要將函數(shù)和對(duì)象添加到模塊的根目錄,您可以將它們添加到特殊的導(dǎo)出對(duì)象。
模塊本地的變量將是私有的,就像模塊被包裝在一個(gè)函數(shù)中一樣。 在這個(gè)例子中,變量 PI 是 circle.js 私有的。
如果您希望模塊導(dǎo)出的根是一個(gè)函數(shù)(例如構(gòu)造函數(shù)),或者如果您想在一次分配中導(dǎo)出一個(gè)完整的對(duì)象而不是一次構(gòu)建一個(gè)屬性,請(qǐng)將其分配給 module.exports 而不是 exports.
例子:
const square = require('./square.js'); var mySquare = square(2); console.log(`The area of my square is ${mySquare.area()}`);
square.js 的實(shí)現(xiàn):
// Assigning to exports will not modify module, must use module.exports module.exports = function (width) { return { area: function () { return (width * width); } }; }
我們來單步調(diào)試一個(gè)實(shí)際例子來加深理解:
上圖是一個(gè)自執(zhí)行函數(shù),兩個(gè)輸入?yún)?shù) global 和 factory 分別傳入了 this 和 function(exports)...
要導(dǎo)出的函數(shù) log 的實(shí)現(xiàn)體,只是一個(gè)簡單的 console.log.
上圖這個(gè) require 其實(shí)是 Node.js 內(nèi)部實(shí)現(xiàn):
當(dāng)前 module 是 local.js 即 node 命令啟動(dòng)的 module,期望加載的 是 log.js:
從 module 的 paths 數(shù)組里就能看出 Node.js 解析 module 的路徑:從當(dāng)前 module 所在的文件夾出發(fā),一直回溯到 c 盤根目錄下的 node_modules
log.js 的 paths:
load 之前先 compile:
第 1157 行的代碼位置,變量 content 的內(nèi)容就是 log.js 文件的內(nèi)容:
compile 的邏輯就是執(zhí)行 log.js 里的代碼:
在這個(gè)上下文里,factory 指向的就是下圖綠色高亮的函數(shù):
define 為 undefined,所以進(jìn)入 else 分支:
此處把 log 函數(shù)寫入到 exports 對(duì)象的 log 屬性里:
然后在我們的應(yīng)用代碼里,就可以使用導(dǎo)出的 log 函數(shù)了:
聯(lián)系客服