Appearance
JavaScript 模块化
作用
- 不污染全局命名空间。
- 像 Java Class 中存在 private public 等定义属性作用域的变量。但是 JS 中不存在。那么模块化就可很好的解决此问题,而不需要借助函数。
- 更好的分离,按需加载
- 高复用性
- 高可维护性
因为模块是独立的,一个设计良好的模块会让外面的代码对自己的依赖越少越好,这样自己就可以独立去更新和改进。
AMD CMD COMMONJS 和 ES6 模块化
- CommonJs 是服务器端的 JS 模块化规范,NodeJs 就是遵循此规范。
- AMD、CMD 都是浏览器端的 JS 模块化规范
CommonJS
CommonJS 加载模块是同步的,所以只有前面的加载完成了才会执行后面的操作。而 NodeJs 中所有的文件都存放在磁盘中所以加载很快,
但是浏览器需要从服务器中加载文件。那么这种规范就没有用了,所以出现了 AMD、CMD 规范。
AMD(异步模块定义)和 CMD(通用模块定义)
- AMD--RequireJS
AMD 规范通过 define 方法去定义模块,通过 require 方法去加载模块。RequireJS 实现了这种规范。
- CMD-Sea.js
CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。
AMD 和 CMD 的区别
对依赖模块的执行时机处理不同,注意不是加载的时机或者方式不同
- 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从 2.0 开始,也改成可以延执行(根据写法不同,处理方式不同)。
CMD 推崇 as lazy as possible(尽可能的懒加载,也称为延迟加载,即在需要的时候才加载)。
- CMD 推崇依赖就近,AMD 推崇依赖前置。
虽然 AMD 也支持 CMD 的写法,同时还支持将 require 作为依赖项传递,但 RequireJS 的作者默认是最喜欢上面的写法,也是官方文档里默认的模块定义写法。
- AMD 的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。
比如 AMD 里,require 分全局 require 和局部 require,都叫 require。
CMD 里,没有全局 require,而是根据模块系统的完备性,提供 seajs.use 来实现模块系统的加载启动。CMD 里,每个 API 都简单纯粹。
ES6 模块化
ES6 模块化的核心思想是 尽量静态化,使得编译时就能确认模块间的依赖关系、以及输出输入的变量。而 AMD、CMD、COMMONJS 是在运行时确认这些东西。
ES6 模块化编译时加载,使得静态分析成为可能,促使了 类型校验、宏 的实现。
- CommonJS
- Node.js : 服务器端
- Browserify : 浏览器端 也称为 js 的打包工具
- 基本语法:
- 定义暴露模块 : exports
exports.xxx = value module.exports = value
引入模块 : requirevar module = require('模块名/模块相对路径')
- 引入模块发生在什么时候?
- Node : 运行时, 动态同步引入
- Browserify : 在运行前对模块进行编译/转译/打包的处理(已经将依赖的模块包含进来了), 运行的是打包生成的 js, 运行时不存在需要再从远程引入依赖模块
- 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'] } } })
- CMD : 浏览器端
- sea.js
- 基本语法
- 定义暴露模块:
define(function(require, module, exports){ 通过require引入依赖模块 通过module/exports来暴露模块 exports.xxx = value })
- 使用模块 seajs.use(['模块 1', '模块 2'])
- 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--->打包处理----浏览器可以运行