Skip to content

JavaScript 模块化

作用

  1. 不污染全局命名空间。
  2. 像 Java Class 中存在 private public 等定义属性作用域的变量。但是 JS 中不存在。那么模块化就可很好的解决此问题,而不需要借助函数。
  3. 更好的分离,按需加载
  4. 高复用性
  5. 高可维护性

因为模块是独立的,一个设计良好的模块会让外面的代码对自己的依赖越少越好,这样自己就可以独立去更新和改进。

AMD CMD COMMONJS 和 ES6 模块化

  • CommonJs 是服务器端的 JS 模块化规范,NodeJs 就是遵循此规范。
  • AMD、CMD 都是浏览器端的 JS 模块化规范

CommonJS

CommonJS 加载模块是同步的,所以只有前面的加载完成了才会执行后面的操作。而 NodeJs 中所有的文件都存放在磁盘中所以加载很快,

但是浏览器需要从服务器中加载文件。那么这种规范就没有用了,所以出现了 AMD、CMD 规范。

AMD(异步模块定义)和 CMD(通用模块定义)

  1. AMD--RequireJS

AMD 规范通过 define 方法去定义模块,通过 require 方法去加载模块。RequireJS 实现了这种规范。

  1. CMD-Sea.js

CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。

AMD 和 CMD 的区别

对依赖模块的执行时机处理不同,注意不是加载的时机或者方式不同

  1. 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从 2.0 开始,也改成可以延执行(根据写法不同,处理方式不同)。

CMD 推崇 as lazy as possible(尽可能的懒加载,也称为延迟加载,即在需要的时候才加载)。

  1. CMD 推崇依赖就近,AMD 推崇依赖前置。

虽然 AMD 也支持 CMD 的写法,同时还支持将 require 作为依赖项传递,但 RequireJS 的作者默认是最喜欢上面的写法,也是官方文档里默认的模块定义写法。

  1. AMD 的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。

比如 AMD 里,require 分全局 require 和局部 require,都叫 require。

CMD 里,没有全局 require,而是根据模块系统的完备性,提供 seajs.use 来实现模块系统的加载启动。CMD 里,每个 API 都简单纯粹。

ES6 模块化

ES6 模块化的核心思想是 尽量静态化,使得编译时就能确认模块间的依赖关系、以及输出输入的变量。而 AMD、CMD、COMMONJS 是在运行时确认这些东西。

ES6 模块化编译时加载,使得静态分析成为可能,促使了 类型校验、宏 的实现。

  1. CommonJS
  • Node.js : 服务器端
  • Browserify : 浏览器端 也称为 js 的打包工具
  • 基本语法:
  • 定义暴露模块 : exports exports.xxx = value module.exports = value 引入模块 : require var module = require('模块名/模块相对路径')
  • 引入模块发生在什么时候?
  • Node : 运行时, 动态同步引入
  • Browserify : 在运行前对模块进行编译/转译/打包的处理(已经将依赖的模块包含进来了), 运行的是打包生成的 js, 运行时不存在需要再从远程引入依赖模块
  1. AMD : 浏览器端
  • require.js
  • 基本语法
  • 定义暴露模块: define([依赖模块名], function(){return 模块对象})
  • 引入模块: require(['模块 1', '模块 2', '模块 3'], function(m1, m2){//使用模块对象})
  • 配置: require.config({ //基本路径 baseUrl : 'js/', //标识名称与路径的映射 paths : { '模块1' : 'modules/模块1', '模块2' : 'modules/模块2', 'angular' : 'libs/angular', 'angular-messages' : 'libs/angular-messages' }, //非AMD的模块 shim : { 'angular' : { exports : 'angular' }, 'angular-messages' : { exports : 'angular-messages', deps : ['angular'] } } })
  1. CMD : 浏览器端
  • sea.js
  • 基本语法
  • 定义暴露模块: define(function(require, module, exports){ 通过require引入依赖模块 通过module/exports来暴露模块 exports.xxx = value })
  • 使用模块 seajs.use(['模块 1', '模块 2'])
  1. ES6
  • ES6 内置了模块化的实现

  • 基本语法

  • 定义暴露模块 : export

  • 暴露一个对象: export default 对象

  • 暴露多个: export var xxx = value1 export let yyy = value2 var xxx = value1 let yyy = value2 export {xxx, yyy}

  • 引入使用模块 : import

  • default 模块: import xxx from '模块路径/模块名'

  • 其它模块 import {xxx, yyy} from '模块路径/模块名' import * as module1 from '模块路径/模块名'

  • 问题: 所有浏览器还不能直接识别 ES6 模块化的语法

  • 解决:

  • 使用 Babel 将 ES6--->ES5(使用了 CommonJS) ----浏览器还不能直接支行

  • 使用 Browserify--->打包处理----浏览器可以运行