JavaScript - 關(guān)于 CommonJs AMD CMD 的簡單使用.

模塊無非就是把一些通用的定義成文件.
起到復(fù)用,結(jié)構(gòu)層次清晰,后期好維護(hù)等好處.

不管是什么 CommonJS , AMD 還是 CMD.
最主要的就是要先摸清三個(gè)事情.

  • 如何定義模塊?
  • 如何使用模塊?
  • 這些模塊的代碼是在哪里跑的?

CommonJS

Node.js 實(shí)現(xiàn)了 CommonJS 的模塊化規(guī)范.(跑在后臺服務(wù)器的)

CommonJs 提供了四個(gè)環(huán)境變量,為模塊化提供了支持.(模塊是怎么定義以及怎么使用的)

  • module
  • expors
  • require
  • global

實(shí)際使用時(shí)

  • 使用 require 來導(dǎo)入你需要使用到的模塊.
  • 使用 exports.xxx 或者 moudle.exports 帶導(dǎo)出當(dāng)前模塊輸出的接口.

一般推薦使用 module.export = {} 的方式.而非 exports.xxx


// 定義 math.js 模塊.

function plus(num1,num2) {
    return num1 + num2
}

// exports.plus = plus 不推薦這種寫法.

module.exports = {
    plus
}

// 使用 math.js 模塊
// main.js

const math = require('./math')
math.plus(1,2)

CommonJs 使用同步的方式加載模塊.
模塊執(zhí)行的環(huán)境在本地的服務(wù)器的Node環(huán)境中.

一切都是這么的和諧自然.

一般后端開發(fā)語言都包含模塊.

比如:

  • java 的 import
  • c# 的 using
  • Node 的 require

AMD & RequireJS

AMD 全稱是 Asynchronous Module Definition.

AMD 模塊是跑在瀏覽器環(huán)境中的.(跑在前端瀏覽器中的)

AMD 規(guī)范采用了異步的方式加載模塊,模塊的加載不影響它后續(xù)的語句執(zhí)行.
所以依賴這個(gè)模塊的語句,都定義在后面的那個(gè)回調(diào)函數(shù)中.
并以參數(shù)的形式提供.
等到所有依賴的模塊都加載完畢之后,這個(gè)回調(diào)函數(shù)才會執(zhí)行.

它是瀏覽器端的一種模塊化異步加載的規(guī)范.

requireJS 實(shí)現(xiàn)了 AMD 的這套標(biāo)準(zhǔn).

使用 requireJS 提供的幾個(gè)簡單的 API 接口,就可以讓我們實(shí)現(xiàn)前端模塊化的開發(fā).(模塊怎么定義以及怎么使用的.)

  • 使用 requireJS 提供的 define() 來定義模塊.
  • 使用 requireJS 提供的 require() 來使用模塊.

當(dāng)然,這里的前端化組件開發(fā),肯定就是不之間的那種多個(gè) <script></script> 按順序?qū)氲哪欠N情況了.
AMD 實(shí)際會根據(jù) define() 或者 require() 中依賴的模塊內(nèi)容,異步的加載對應(yīng)的js文件.

step 1

首先要去 requireJS 官網(wǎng)下載 requirejS 文件.

step 2

新建一個(gè) index.html,并導(dǎo)入我們下載好的這個(gè) requireJS .

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>AMD-Asynchronous Module Definition</title>
</head>
<body>
  <div id="app"></div>
</body>
</html>
<!-- 導(dǎo)入 require.js -->
<script src="./js/require.js" async="true" defer data-main="./js/main.js"></script>

其中

  • async='true' 是 script 標(biāo)簽提供的功能,可以異步的下載js文件,不會導(dǎo)致瀏覽器阻塞.
  • defer 是因?yàn)?IE 瀏覽器目前不支持 async.
  • data-main 是給 requirejs 指定入口的 js 文件.(就和 webpack 打包工具指定 entry 一樣)

這里的

<script src="./js/require.js" async="true" defer data-main="./js/main.js"></script>

做了兩件事情:

  • 導(dǎo)入 require.js 文件.
  • main.js 做為整個(gè)前端模塊的入口.

step 3

定義一個(gè) main.js 需要使用到的模塊.

既然這里使用到的是 requirejs 提供的前端化模塊方案.
那么肯定就不能像沒事人那樣寫以前的那種js代碼文件了.

requireJs 提供了一個(gè)全局的 define(name?,[dependencies]?,factory)

用來定義一個(gè) AMD 的模塊.

其中:

  • name : 模塊的名字.(一般很少用到這個(gè)參數(shù))
  • dependencies : 當(dāng)前模塊依賴的模塊.數(shù)據(jù)類型
  • factory: 一個(gè)工廠函數(shù),用于返回當(dāng)前模塊的API.

代碼格式

define(['moduleA','moduleB','moduleC'],function(moduleA,moduleB,moduleC) {
    // 等待 moduleA , moduleB, moduleC 都加載完畢之后,會進(jìn)入到這個(gè)回調(diào)函數(shù).
    
    moduleA.someFn()
    moduleB.someFn()
    moduleC.someFn()
    
    // 這個(gè)對象就是當(dāng)前定義模塊返回的API.內(nèi)容.
    return {
        a: moduleA.xxx,
        b: moduleB.xxx,
        c: moduleC.xxx
    }
})

step 4.編造一個(gè)場景,使用rquirejs提供的define()來定義一個(gè)模塊

regex.js 一個(gè)提供正則表達(dá)式驗(yàn)證的AMD模塊.

define(function () { 
  const phoneRegex = /^(13|14|15|17|18|19)[0-9]{9}$/, // 手機(jī)號碼(國內(nèi))
        emailRegex = /^\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}$/ // 郵箱
  
  function isPhoneNum (phone) { 
    return phoneRegex.test(phone)
  }

  function isEmail (email) {
    return emailRegex.test(email)
  }

  // 此模塊返回兩個(gè)函數(shù)
  return {
    isPhoneNum,
    isEmail
  }
})

  • 這里的 regex.js 是一個(gè)很簡單的正則驗(yàn)證模塊.沒有依賴其他的模塊功能.所以使用了 define(factory) 來定義.
  • 模塊最終返回了一個(gè)對象,里面包括了兩個(gè)函數(shù)(isPhoneNum,isEmail)

step 5. 使用RequireJS提供的require()來引用regex模塊

main.js (入口模塊) 使用 regex.js 模塊文件.

既然這里使用到的是 requirejs 提供的前端化模塊方案.
引用模塊需要使用到 requirejs 提供的 require 接口角寸。

RequireJS 提供了一個(gè)全局的 require([dependencies],factory)

用來引用一個(gè) AMD 模塊(define()定義的)

其中

  • dependencies : 當(dāng)前require依賴的js模塊. 是一個(gè)數(shù)組.
  • factory : 當(dāng)所有模塊都加載完成之后.會觸發(fā)這個(gè)回調(diào)函數(shù).函數(shù)形參是按照模塊的導(dǎo)入順序賦值的.

代碼格式

require(['moduleA','moduleB','moduleC'],function(){
    moduleA.someFn()
    moduleB.someFn()
    moduleC.someFn()
})

index.html 導(dǎo)入的

<script src="./js/lib/require.js" async="true" defer data-main="./js/main.js"></script>

main.js 文件中.


require(['./module/regex'], function (regex) { 
  document.getElementById('phone').onblur = function (e) { 
    const value = e.target.value
    let result = regex.isPhoneNum(value) ? '手機(jī)號碼正確' : '手機(jī)號碼錯(cuò)誤'
    console.log(result)
  }

  document.getElementById('email').onblur = (event) => {
    const value = event.target.value
    let result = regex.isEmail(value) ? '郵箱賬號正確' : '郵箱賬號錯(cuò)誤'
    console.log(result)
  }
})

最后測試結(jié)果:

image.png

AMD總結(jié):

  • 需要在頁面中首先加載 requirejS 文件. 并設(shè)置入口模塊.(main.js)
<script src="./js/lib/require.js" async="true" defer data-main="./js/main.js"></script>
  • 定義AMD模塊使用 RequireJS 提供的 define(name?,[dependencies]?,factory) 方法定義模塊.
// AMD 在定義模塊時(shí),提倡依賴前置
define(['moduleA','moduleB'],function(moduleA,moduleB){

    // some code here with moduleA...moduleB
})
  • 導(dǎo)入 AMD 模塊使用 RequreJS 提供的 require([dependencies],factory) 方法導(dǎo)入并使用模塊.
AMD 在使用模塊時(shí),提倡依賴前置
require(['moduleA','moduleB'],function(moduleA,moduleB){
    // some code here with moduleA...moduleB
})

CMD & sea.js

CMD 是 Common Module Definition 的縮寫.

它和 AMD 一樣,也是用于前端瀏覽器模塊化開發(fā)的一個(gè)標(biāo)準(zhǔn).(跑在前端瀏覽器中的)

國內(nèi)大神根據(jù)此標(biāo)準(zhǔn)創(chuàng)建了 sea.js .

為什么有了AMD之后,還要有一個(gè)CMD呢?

AMD & require.js 提倡的是依賴前置.

define(['a','b','c'],function(a,b,c){
    
})

而 CMD 和 AMD 不同之處在于:

CMD 提倡依賴后置,或者說懶加載依賴.只有在使用到某些框架的時(shí)候,才去加載依賴.

define(function(require,exports,module){
    const moduleA = require('a')
    if (moduleA.test()) {
        // 只有在需要這個(gè)模塊的時(shí)候,才去加載.
        const moduleB = require('b')
        //.....
    }
})

實(shí)現(xiàn)了 CMD 標(biāo)準(zhǔn)的 sea.js 也提供了定義模塊使用模塊的方法.(模塊怎么定義以及怎么使用的)

  • CMD 定義模塊使用
// math.js
define(function(require,exports,module){
    function add (a, b) {
      return a + b
    }

  module.exports = {
    add
  }
})
  • CMD 導(dǎo)入模塊使用
// main.js
seajs.use(['./math.js'],function(math){
    math.add(1,2)
})

CMD&sea.js 的基本使用步驟.

step 1.需要下載sea.js源代碼

<script src="./sea.3.0.3.js"></script>

和 require.js 不同的是, sea.js 不是指定所謂 data-main 入口js文件.
sea.js 提供一個(gè)全局的 seajs.use([dependencies],callback) 接口,用來使用定義的 CMD 模塊.

step 2.

創(chuàng)建一個(gè) regex.js 的正則表達(dá)式驗(yàn)證模塊.

//regex.js

define(function (require, exports, module) {
  const phoneRegex = /^(13|14|15|17|18|19)[0-9]{9}$/, // 手機(jī)號碼(國內(nèi))
    emailRegex = /^\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}$/ // 郵箱

  function isPhoneNum(phone) {
    return phoneRegex.test(18571656584)
  }

  function isEmail(email) {
    return emailRegex.test(email)
  }

// 和 commonJS很類似的導(dǎo)出語法.
  module.exports = {
    isPhoneNum,
    isEmail
  }
})

注意:

sea.js 提供的是一個(gè)和 commonjs 原理很類似的模塊定義方法.(利用閉包函數(shù)包裹的方式)

step 3.

創(chuàng)建一個(gè)使用此模塊的 main.js 文件

// main.js

seajs.use(['./regex.js'], function (regex) {
  window.onload = () => {
    document.getElementById('18571656584').onblur = function (e) {
      const value = e.target.value
      let result = regex.isPhoneNum(value) ? 'CMD-SEAJS-手機(jī)號碼正確' : 'CMD-SEA-JS手機(jī)號碼錯(cuò)誤'
      console.log(result)
    }
    document.getElementById('email').onblur = (event) => {
      const value = event.target.value
      let result = regex.isEmail(value) ? 'CMD-SEA-JS郵箱賬號正確' : 'CMD-SEA-JS郵箱賬號錯(cuò)誤'
      console.log(result)
    }
  }
})

sea.js 使用全局提供的 seajs.use() 來使用模塊.

step 4.

在界面中導(dǎo)入這個(gè)js文件.

<script src="./main.js"></script>

step 5.

結(jié)果:

image.png

CMD模塊使用步驟總結(jié)

  • 首先要下載sea.js源代碼,并在頁面中導(dǎo)入此文件虏两。
<script src="./sea.3.0.3.js"></script>
  • 使用 seajs 提供的define()函數(shù)定義 CMD 模塊.
define(function(require,exports,module){
    //..
    
    if (someCondition) {
        // CMD 在導(dǎo)入模塊是提倡依賴后置
        const m = require('./someModule.js')
    }
    
    module.exports = {}
})
  • 利用 seajs 提供的 seajs.use([dependencies],callback) 來使用定義好的模塊.
seajs.use(['a,'b'],function(a,b) {
    //....
})

總結(jié):

  • 前端模塊化指的是在瀏覽器執(zhí)行環(huán)境中的模塊化.
  • 提供前端模塊化的方式有兩種.
    • AMD 異步模塊定義和實(shí)現(xiàn)了此標(biāo)準(zhǔn)的 requireJs
      • AMD 提倡依賴前置.
      • 使用 define() 來定義模塊.
      • 使用 require() 來使用模塊.
    • CMD 通用模塊定義和實(shí)現(xiàn)了此標(biāo)準(zhǔn)的 seajs
      • CMD 提倡依賴后置.
      • 使用 define(function(require,exports,module){}) 來定義模塊.
      • 使用全局提供的 seajs.use([dependencies],callback) 來使用模塊.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末晶姊,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌肺孤,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件误褪,死亡現(xiàn)場離奇詭異春叫,居然都是意外死亡肩钠,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進(jìn)店門暂殖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來价匠,“玉大人,你說我怎么就攤上這事呛每〔冉眩” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵晨横,是天一觀的道長洋腮。 經(jīng)常有香客問我箫柳,道長,這世上最難降的妖魔是什么啥供? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任悯恍,我火速辦了婚禮,結(jié)果婚禮上伙狐,老公的妹妹穿的比我還像新娘涮毫。我一直安慰自己,他們只是感情好贷屎,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布窒百。 她就那樣靜靜地躺著,像睡著了一般豫尽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上顷帖,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天美旧,我揣著相機(jī)與錄音,去河邊找鬼贬墩。 笑死榴嗅,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的陶舞。 我是一名探鬼主播嗽测,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼肿孵!你這毒婦竟也來了唠粥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤停做,失蹤者是張志新(化名)和其女友劉穎晤愧,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蛉腌,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡官份,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了烙丛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片舅巷。...
    茶點(diǎn)故事閱讀 40,137評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖河咽,靈堂內(nèi)的尸體忽然破棺而出钠右,到底是詐尸還是另有隱情,我是刑警寧澤库北,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布爬舰,位于F島的核電站们陆,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏情屹。R本人自食惡果不足惜坪仇,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望垃你。 院中可真熱鬧椅文,春花似錦、人聲如沸惜颇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽凌摄。三九已至羡蛾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間锨亏,已是汗流浹背痴怨。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留器予,地道東北人浪藻。 一個(gè)月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像乾翔,于是被迫代替她去往敵國和親爱葵。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評論 2 355