寫乙個適應所有環境的js模組

2022-08-30 14:09:21 字數 1986 閱讀 3439

說下背景:

在es6以前,js語言沒有模組化,如何讓js不止執行在瀏覽器,且能更有效的管理**,

於是應運而生commonjs這種規範,定義了三個全域性變數:

require,exports,module
require 用於引入乙個模組

exports 對外暴露模組的介面,可以是任何型別

module 是這個模組本身的物件

用require引入時獲取的是這個模組對外暴露的介面(exports)

node.js 使用了commonjs規範:

在瀏覽器端,不像node.js內部支援commonjs,如何進行模組化,

於是出現了 cmd 與 amd 兩種方式,其主要代表是 seajs 和 requirejs,

他們都定義了乙個全域性函式 define 來建立乙個模組:

可以看出cmd完好的保留了commonjs的風格,

而amd用了一種更簡潔的依賴注入和函式返回的方式實現模組化。

兩者除風格不同外最大區別在於載入依賴模組的方式,

cmd是懶載入,在require時才會載入依賴,

而amd是預載入,在定義模組時就提前載入好所有依賴。

各有千秋,各有適合的場景,網上有兩者詳細評測和激烈的討論。

背景介紹完,說正題。

我們要實現乙個模組,讓它既能在seajs(cmd)環境裡引入,又能在requirejs(amd)環境中引入,

當然也能在node.js(commonjs)中使用,另外還可以在沒有模組化的環境中用script標籤全域性引入,

可謂是對write once,run anywhere的嚮往,實際上大部分npm的前端元件包也要考慮這個。

首先乙個模組看起來應該是這樣:

當然,模組輸出的不止可以是物件,還是可以是任何值,包括乙個類。

分析cmd和amd,我們需要提供乙個工廠函式傳入define來定義模組,所以變成這樣:

為適應node.js,可以來判斷全域性變數,由於require在cmd和adm中都有定義,所以只判斷:

typeof module !== 'undefined' && typeof exports === 'object'
於是變成這樣:

至此已經能夠滿足node.js的需求。

當沒有上述全域性變數,且有define全域性變數時,我們認為是amd或cmd,可以直接將factory傳入define:

注意:cmd其實也支援return返回模組介面,所以兩者可以通用。

最後是script標籤全域性引入,我們可以將模組放在window上,

為了模組內部在瀏覽器和node.js中都能使用全域性物件,我們可以做此判斷:

var global = typeof window !== 'undefined' ? window : global;
同時,我們用乙個立刻執行的閉包函式將所有**包含,來避免汙染全域性空間,

並將global物件傳入閉包函式,最終變成這樣:

注意:閉包前加上分號是為了給前乙個模組填坑,分號多了沒問題,少了則語句可能發生變化。

於是同乙個js檔案我們能愉快的在不同環境這樣引入:

js寫乙個外掛程式

分號開頭,用於防止 壓縮合併時與其它 混在一起造成語法錯誤 而事實證明,uglify壓縮工具會將無意義的前置分號去掉,我只是習慣了這麼寫 function 立即執行函式,閉包,避免汙染全域性變數 通常乙個外掛程式只暴露乙個變數給全域性供其它程式呼叫 還有其它寫法,運算子 函式體 括號 例 funct...

Linux 寫乙個簡單的模組

1.建立乙個目錄 mkdir zhu cd zhu vim hello.c 編寫乙個名為hello的檔案 2.hello.c include 所有模組都需要的標頭檔案 include static int hello init void static void hello exit module i...

開始寫乙個核心模組

從hello world開始,乙個完整的核心模組helloword.c如下 include module init 和 module exit 的標頭檔案 include 這個標頭檔案包含了許多符號與函式的定義,這些符號與函式多與載入模組有關 module license dual bsd gpl ...