欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JS模块化规范(AMD/CMD/CommonJS/UMD/ES6 Module)

程序员文章站 2022-06-13 22:05:29
...

为什么需要模块化

以功能为单位进行程序设计,实现其求解算法的方法称为模块化,原则是“高内聚,低耦合”。模块化的目的是为了降低程序的复杂度,使程序设计、调试和维护等操作变得简单化。
随着互联网行业的发展,网站越来越复杂,实现网站功能的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://github.com/umdjs/umd

参考链接

转载于:https://www.jianshu.com/p/f776f2c6709a