模块无非就是把一些通用的定义成文件.
起到复用,结构层次清晰,后期好维护等好处.
不管是什么 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()
来使用模块.
当然,这里的前端化组件开发,肯定就是不之间的那种多个
<script></script>
按顺序导入的那种情况了.
AMD 实际会根据 define() 或者 require() 中依赖的模块内容,异步的加载对应的js文件.
step 1
首先要去 requireJS
官网下载 requirejS 文件.
step 2
新建一个 index.html
,并导入我们下载好的这个 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>
<!-- 导入 require.js -->
<script src="./js/require.js" async="true" defer data-main="./js/main.js"></script>
其中
-
async='true'
是 script 标签提供的功能,可以异步的下载js文件,不会导致浏览器阻塞. -
defer
是因为 IE 浏览器目前不支持async
. -
data-main
是给requirejs
指定入口的js
文件.(就和 webpack 打包工具指定 entry 一样)
这里的
<script src="./js/require.js" async="true" defer data-main="./js/main.js"></script>
做了两件事情:
- 导入
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
导入的
<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) ? '手机号码正确' : '手机号码错误'
console.log(result)
}
document.getElementById('email').onblur = (event) => {
const value = event.target.value
let result = regex.isEmail(value) ? '邮箱账号正确' : '邮箱账号错误'
console.log(result)
}
})
最后测试结果:
AMD总结:
- 需要在页面中首先加载 requirejS 文件. 并设置入口模块.(
main.js
)
<script src="./js/lib/require.js" async="true" defer data-main="./js/main.js"></script>
- 定义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源代码
<script src="./sea.3.0.3.js"></script>
和 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文件.
<script src="./main.js"></script>
step 5.
结果:
CMD模块使用步骤总结
- 首先要下载sea.js源代码,并在页面中导入此文件。
<script src="./sea.3.0.3.js"></script>
- 使用 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)
来使用模块.
-
-