JS模块化规范(AMD/CMD/CommonJS/UMD/ES6 Module)
为什么需要模块化
以功能为单位进行程序设计,实现其求解算法的方法称为模块化,原则是“高内聚,低耦合”。模块化的目的是为了降低程序的复杂度,使程序设计、调试和维护等操作变得简单化。
随着互联网行业的发展,网站越来越复杂,实现网站功能的Javacript代码越来越庞大,随之也暴露出了全局变量冲突、函数命名冲突、依赖关系处理等很多问题。
在模块化方案提出之前,聪明又伟大的前端工程师们想出了两个很好的解决方案:
1. 添加命名空间 即使用对象的字面量的方式来管理模块,一个对象就是一个模块,把函数和属性都封装在对象里,示例代码如下
var module_a = {
_index:0,
fn1:function(){...}
}
var module_b = {
fn1:function(){...}
}
以上代码,module_a和module_b分别作为两个模块的命名空间,这样就可以通过命名空间来分开定义和调用两个fn1方法
module_a .fn1();
module_b .fn1();
通常带下滑线的属性表示该属性为私有属性,以上代码 module_a中的_index对外暴露,并可被修改,代码如下。
module_a._index = 1;
这怎么能忍,实现私有属性还不简单,上闭包大法!于是有了下面一种模块化方式。
2. 立即执行函数
var module_a = (function(){
var _index = 0;
function fn1(){
console.log(index)
}
return {
fn1:fn1
}
})()
以上代码定义了一个立即执行的匿名函数,匿名函数可以形成一个独立的作用域,用匿名函数作为一个“容器”,“容器”内部可以访问外部的变量,而外部环境不能访问“容器”内部的变量,所以匿名函数内部定义的变量不会与外部的变量发生冲突。
这种方法既避免了命名冲突,又使得私有变量_index不能被外界访问和修改,jQuery和Zepto源码中大量使用的这种方式。
常见的模块化方案
目前开发中,流行的模块化规范主要有CommonJS、AMD、CMD、ES6 Module。比方说,CommonJS规范的实现代表是Nods.js,AMD规范的实现代表是RequireJS,CMD规范的实现代表是Sea.js。
1 CommonJS规范
在Node.js中,通过全局方法 require()加载模块
let http = require('http');
Node.js内部提供一个Module构建函数,所有的模块都是Module的实例。如在node环境下,打印module,将会得到以下结果
// module1.js
console.dir(module)
// module2.js
let module1 = require('./module1')
控制台打印以下结果
Module {
id: 'E:\\module-manager\\commonjs\\text.js',
exports: [Function],
parent:
Module {
id: '.',
exports: {},
parent: null,
filename: 'E:\\module-manager\\commonjs\\demo.js',
loaded: false,
children: [ [Circular] ],
paths:
[ 'E:\\module-manager\\commonjs\\node_modules',
'E:\\module-manager\\node_modules',
'E:\\node_modules' ] },
filename: 'E:\\module-manager\\commonjs\\text.js',
loaded: false,
children: [],
paths:
[ 'E:\\module-manager\\commonjs\\node_modules',
'E:\\module-manager\\node_modules',
'E:\\node_modules' ] }
- id: 模块标识符,通常是带有绝对路径的模块文件名。文件本身则为 '.'
- exports: 标识模块对外输出的值。
- parent: 返回一个对象,标识调用该模块的函数。
- filename: 模块文件名,带有绝对路径。
- loaded: 返回一个布尔值,标识模块是否已经加载。
- children: 返回一个数组,表示该模块要用到的其他模块
- paths: 返回一个数组,表示在该模块中,使用require方法加载三方模块的顺序。
模块导出的方式除了使用 module.exports = xxx,还可以这么使用
// module2.js
exports.module2 = function(param){
console.log(param)
}
注意,不能把值直接赋值给exports,因为这样等于切断了exports与module.exports的联系。
总结CommonJS模块的特点如下:
- 所有的模块都有单独的作用域,不会污染全局作用域,即一个文件为一个模块。
- 重复加载模块只会加载一次,后面的都从缓存读取。
- 模块加载的顺序按照代码中出现的顺序。
- 模块加载是同步的。
2 AMD规范 (Asynchronous Module Definition 异步模块定义)
CommonJS模块采用同步加载,适合服务器却不适合浏览器。AMD规范支持异步加载模块,规范中定义了一个全局变量define函数,描述如下
define(id?,dependcies?,factory)
3CMD规范 (Common Module Definition 通用模块定义)
4 ES6 Module
seajs https://github.com/seajs/seajs
https://seajs.github.io/seajs/docs/
AMD (Asynchronous Module Definition 异步模块定义)
https://github.com/amdjs/amdjs-api
https://github.com/requirejs/requirejs
https://requirejs.org/
UMD (Universal Module Definition 统一模块定义)
参考链接
转载于:https://www.jianshu.com/p/f776f2c6709a
推荐阅读
-
再次梳理AMD、CMD、CommonJS、ES6 Module的区别
-
JavaScript模块化-CommonJS、AMD、CMD、UMD、ES6
-
前端模块化:CommonJS,CMD,AMD,ES6
-
前端模块化小总结—commonJs,AMD,CMD, ES6 的Module
-
javascript模块化之CommonJS、AMD、CMD、UMD、ES6
-
javascript模块化之CommonJS、AMD、CMD、UMD、ES6
-
JavaScript里面的模块化4种方式(CommonJS,AMD,CMD,es6Module)
-
模块化module/CommonJS/Browserify/AMD/RequireJS/CMD/SeaJS/ES6_Babel
-
前端模块化:AMD, CMD, CommonJS, ES6 Module
-
前端模块化详解(CommonJS、AMD、CMD、ES Module)