JavaScript - 关于 CommonJs AMD CMD 的简单使用.

模块无非就是把一些通用的定义成文件.
起到复用,结构层次清晰,后期好维护等好处.

不管是什么 CommonJS , AMD 还是 CMD.
最主要的就是要先摸清三个事情.

  • 如何定义模块?
  • 如何使用模块?
  • 这些模块的代码是在哪里跑的?

CommonJS

Node.js 实现了 CommonJS 的模块化规范.(跑在后台服务器的)

CommonJs 提供了四个环境变量,为模块化提供了支持.(模块是怎么定义以及怎么使用的)

  • module
  • expors
  • require
  • global

实际使用时

  • 使用 require 来导入你需要使用到的模块.
  • 使用 exports.xxx 或者 moudle.exports 带导出当前模块输出的接口.

一般推荐使用 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 使用同步的方式加载模块.
模块执行的环境在本地的服务器的Node环境中.

一切都是这么的和谐自然.

一般后端开发语言都包含模块.

比如:

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

AMD & RequireJS

AMD 全称是 Asynchronous Module Definition.

AMD 模块是跑在浏览器环境中的.(跑在前端浏览器中的)

AMD 规范采用了异步的方式加载模块,模块的加载不影响它后续的语句执行.
所以依赖这个模块的语句,都定义在后面的那个回调函数中.
并以参数的形式提供.
等到所有依赖的模块都加载完毕之后,这个回调函数才会执行.

它是浏览器端的一种模块化异步加载的规范.

requireJS 实现了 AMD 的这套标准.

使用 requireJS 提供的几个简单的 API 接口,就可以让我们实现前端模块化的开发.(模块怎么定义以及怎么使用的.)

  • 使用 requireJS 提供的 define() 来定义模块.
  • 使用 requireJS 提供的 require() 来使用模块.

当然,这里的前端化组件开发,肯定就是不之间的那种多个 按顺序导入的那种情况了.
AMD 实际会根据 define() 或者 require() 中依赖的模块内容,异步的加载对应的js文件.

step 1

首先要去 requireJS 官网下载 requirejS 文件.

step 2

新建一个 index.html,并导入我们下载好的这个 requireJS .




  
  
  
  AMD-Asynchronous Module Definition


  

其中

  • async='true' 是 script 标签提供的功能,可以异步的下载js文件,不会导致浏览器阻塞.
  • defer 是因为 IE 浏览器目前不支持 async.
  • data-main 是给 requirejs 指定入口的 js 文件.(就和 webpack 打包工具指定 entry 一样)

这里的


做了两件事情:

  • 导入 require.js 文件.
  • main.js 做为整个前端模块的入口.

step 3

定义一个 main.js 需要使用到的模块.

既然这里使用到的是 requirejs 提供的前端化模块方案.
那么肯定就不能像没事人那样写以前的那种js代码文件了.

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

用来定义一个 AMD 的模块.

其中:

  • name : 模块的名字.(一般很少用到这个参数)
  • dependencies : 当前模块依赖的模块.数据类型
  • factory: 一个工厂函数,用于返回当前模块的API.

代码格式

define(['moduleA','moduleB','moduleC'],function(moduleA,moduleB,moduleC) {
    // 等待 moduleA , moduleB, moduleC 都加载完毕之后,会进入到这个回调函数.
    
    moduleA.someFn()
    moduleB.someFn()
    moduleC.someFn()
    
    // 这个对象就是当前定义模块返回的API.内容.
    return {
        a: moduleA.xxx,
        b: moduleB.xxx,
        c: moduleC.xxx
    }
})

step 4.编造一个场景,使用rquirejs提供的define()来定义一个模块

regex.js 一个提供正则表达式验证的AMD模块.

define(function () { 
  const phoneRegex = /^(13|14|15|17|18|19)[0-9]{9}$/, // 手机号码(国内)
        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)
  }

  // 此模块返回两个函数
  return {
    isPhoneNum,
    isEmail
  }
})

  • 这里的 regex.js 是一个很简单的正则验证模块.没有依赖其他的模块功能.所以使用了 define(factory) 来定义.
  • 模块最终返回了一个对象,里面包括了两个函数(isPhoneNum,isEmail)

step 5. 使用RequireJS提供的require()来引用regex模块

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

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

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

用来引用一个 AMD 模块(define()定义的)

其中

  • dependencies : 当前require依赖的js模块. 是一个数组.
  • factory : 当所有模块都加载完成之后.会触发这个回调函数.函数形参是按照模块的导入顺序赋值的.

代码格式

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

index.html 导入的


main.js 文件中.


require(['./module/regex'], function (regex) { 
  document.getElementById('phone').onblur = function (e) { 
    const value = e.target.value
    let result = regex.isPhoneNum(value) ? '手机号码正确' : '手机号码错误'
    console.log(result)
  }

  document.getElementById('email').onblur = (event) => {
    const value = event.target.value
    let result = regex.isEmail(value) ? '邮箱账号正确' : '邮箱账号错误'
    console.log(result)
  }
})

最后测试结果:

image.png

AMD总结:

  • 需要在页面中首先加载 requirejS 文件. 并设置入口模块.(main.js)

  • 定义AMD模块使用 RequireJS 提供的 define(name?,[dependencies]?,factory) 方法定义模块.
// AMD 在定义模块时,提倡依赖前置
define(['moduleA','moduleB'],function(moduleA,moduleB){

    // some code here with moduleA...moduleB
})
  • 导入 AMD 模块使用 RequreJS 提供的 require([dependencies],factory) 方法导入并使用模块.
AMD 在使用模块时,提倡依赖前置
require(['moduleA','moduleB'],function(moduleA,moduleB){
    // some code here with moduleA...moduleB
})

CMD & sea.js

CMD 是 Common Module Definition 的缩写.

它和 AMD 一样,也是用于前端浏览器模块化开发的一个标准.(跑在前端浏览器中的)

国内大神根据此标准创建了 sea.js .

为什么有了AMD之后,还要有一个CMD呢?

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

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

而 CMD 和 AMD 不同之处在于:

CMD 提倡依赖后置,或者说懒加载依赖.只有在使用到某些框架的时候,才去加载依赖.

define(function(require,exports,module){
    const moduleA = require('a')
    if (moduleA.test()) {
        // 只有在需要这个模块的时候,才去加载.
        const moduleB = require('b')
        //.....
    }
})

实现了 CMD 标准的 sea.js 也提供了定义模块使用模块的方法.(模块怎么定义以及怎么使用的)

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

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

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

step 1.需要下载sea.js源代码


和 require.js 不同的是, sea.js 不是指定所谓 data-main 入口js文件.
sea.js 提供一个全局的 seajs.use([dependencies],callback) 接口,用来使用定义的 CMD 模块.

step 2.

创建一个 regex.js 的正则表达式验证模块.

//regex.js

define(function (require, exports, module) {
  const phoneRegex = /^(13|14|15|17|18|19)[0-9]{9}$/, // 手机号码(国内)
    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很类似的导出语法.
  module.exports = {
    isPhoneNum,
    isEmail
  }
})

注意:

sea.js 提供的是一个和 commonjs 原理很类似的模块定义方法.(利用闭包函数包裹的方式)

step 3.

创建一个使用此模块的 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-手机号码正确' : 'CMD-SEA-JS手机号码错误'
      console.log(result)
    }
    document.getElementById('email').onblur = (event) => {
      const value = event.target.value
      let result = regex.isEmail(value) ? 'CMD-SEA-JS邮箱账号正确' : 'CMD-SEA-JS邮箱账号错误'
      console.log(result)
    }
  }
})

sea.js 使用全局提供的 seajs.use() 来使用模块.

step 4.

在界面中导入这个js文件.


step 5.

结果:

image.png

CMD模块使用步骤总结

  • 首先要下载sea.js源代码,并在页面中导入此文件。

  • 使用 seajs 提供的define()函数定义 CMD 模块.
define(function(require,exports,module){
    //..
    
    if (someCondition) {
        // CMD 在导入模块是提倡依赖后置
        const m = require('./someModule.js')
    }
    
    module.exports = {}
})
  • 利用 seajs 提供的 seajs.use([dependencies],callback) 来使用定义好的模块.
seajs.use(['a,'b'],function(a,b) {
    //....
})

总结:

  • 前端模块化指的是在浏览器执行环境中的模块化.
  • 提供前端模块化的方式有两种.
    • AMD 异步模块定义和实现了此标准的 requireJs
      • AMD 提倡依赖前置.
      • 使用 define() 来定义模块.
      • 使用 require() 来使用模块.
    • CMD 通用模块定义和实现了此标准的 seajs
      • CMD 提倡依赖后置.
      • 使用 define(function(require,exports,module){}) 来定义模块.
      • 使用全局提供的 seajs.use([dependencies],callback) 来使用模块.

你可能感兴趣的:(JavaScript - 关于 CommonJs AMD CMD 的简单使用.)