前端模块化
- 将代码以功能区分,分成各个模块。
模块化演进过程
-
最早期:以文件形式划分
-
- 将js代码分成各个模块文件,以script src引入
-
- 这种模式会带来很多问题:
-
-
- -污染全局变量
-
-
-
- 命名冲突
-
-
-
- 无法管理模块依赖关系
-
-
-
- 完全依靠约定
-
-
第二阶段:命名空间方式
-
- 将方法、变量用JavaScript Object包裹
-
第三阶段: 使用立即执行函数包裹
-
- 实现了私有成员的概念
-
- 用立即执行函数的参数来表名依赖关系
-
以上的形式 非常依赖手动加载模块,以及加载顺序
AMD
实现
- 浏览器端 – require.js
说明
- 依赖必须提前声明好
- 模块加载异步,指定回调函数
基本语法
引入
//通过数组引入依赖,回调函数通过形参传入依赖
define(['Module1', ‘Module2’], function (Module1, Module2) {
function foo () {
/// someing
Module1.test();
}
return {foo: foo}
});
优点
适合在浏览器环境中异步加载模块。可以并行加载多个模块
缺点
提高开发成本,不能按需加载,必须提前加载所有的依赖,使用相对复杂,模块js文件请求频繁
CMD
实现
- 浏览器端 – sea.js
说明
- 对于依赖的模块AMD是提前执行,CMD是延迟执行
- AMD推崇依赖前置 CMD推崇依赖就近
- 整合了commonjs和amd的特点
- 模块的加载是异步的,模块使用时才会加载执行
基本语法
引入
define(function (require, exports, module) {
//依赖可以就近书写
var a = require('./a');
a.test();
...
//软依赖
if (status) {
var b = requie('./b');
b.test();
}
});
define(function(require,exports, module) {
exports.xxx = value
module.exports = value
})
define(function(require,exports, module) {
var module2 = require('./module2')
require.async('./module3', function(module3) {
......
})
module.exports = value
})
优点
可以按需加载,依赖就近
缺点
依赖SPM打包,模块的加载逻辑偏重
COMMON.JS
实现
- 服务端 – node
- 浏览器 – webpack、browserfy
说明
- 模块加载同步,资源加载完再执行
- 每个文件都可以是一个模块
- 服务端 模块加载时运行时同步加载
- 浏览器 模块加载是提前编译打包处理
- 对于基本数据类型,属于复制。会被模块缓存
- 对于复杂数据类型 属于浅拷贝。由于两个模块引用 的对象指向同一个内存空间,值修改会影响另一个模块
- 当使用require命令加载某个模块时,就会运行整个模块的代码
- 当使用require加载同一个模块时,不会再执行该模块,就返回第一次执行的结果
- 循环加载时,属于加载时执行
基本语法
// 引入模块
// 第三方
var fs = require('fs')
//自定义模块
require('./xxx,jpg')
//读入并执行一个js文件,然后返回该模块的exports对象,如果没有就会报错
//暴露模块
module.exports = value
exports.xxx = value
//module变量代表当前模块。这个变量是一个对象,它的exports属性是对外的接口
ES6 MODULE
实现
- 服务端和浏览器通用
- 浏览器端 — 目前需要Babel将es6转成es5、Browserfy编译
说明
- 依赖需要提前声明 import在顶层
- es6模块中的值属于 动态只读引用
- 对于只读来说,不允许修改引入变量的值,当模块遇到import命令时就会生成一个只读引用,等到脚本真正执行时,再根据只读引用,到被加载的那个模块里面去取值
- 对于动态来说,原始值发生变化,import加载的值也会发生变化,不论是什么类型
- 循环加载时,ES6模块是动态引用,只要两个模块之间存在某个引用,代码就能执行
基本语法
//引入
import
import xxx from 'xxx.js'
import {xxx} from 'xxx.js'
//暴露
export
export default module
export module
和commonjs的区别
es6输出的是只读引用、commonjs输出的是值的浅拷贝
因为commonjs加载的是一个对象,该对象只有在脚本运行完才会生成
es6不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成