前言
模块化发展历史
IIFE、AMD、CMD、CommonJS、UMD、ES Modules
模块化作用:抽取公共代码,作用域隔离,依赖隔离
各模块解决的问题及特点:
IIFE是函数级别的作用域,解决了变量作用域问题,仅在该函数中使用
AMD:异步脚本加载
CMD:兼容cjs、amd
UMD:兼容cjs、amd导出
ESM:ES6模块化,适用于ES6静态编译特点\
分析模块化的思路:
# 为解决什么问题;
运行环境(浏览器、服务端常用实例);
语法;
加载特点:导入(同步、异步),导出(是否缓存);
注意事项;
cjs规范详解
运行环境:服务器端node,浏览器端webpack
语法:
(自定义模块)导出:
module.exports = myExportObj // module为模块对象
或者exports.myExportObj = myExportObj // exports为模块对象module.exports的引用,exports = 其他对象,则丢失导出对象的引用关系
导入自定义模块:const module1 = require('./module1.js')
导入第三方模块:const echarts = require('echarts')
运行特点:
-
加载:文件即模块,模块加载同步:服务器端模块加载是运行时同步加载,浏览器模块加载是提前编译打包处理
-
导入导出:exports = module.exports输出(不能给exports赋值,导致与module引用断开), require引入
-
导入导出:require值会缓存,通过require引用文件时,会将文件执行一遍后,将结果通过浅克隆的方式,写入全局内存,后续require该路径,直接从内存获取,无需重新执行文件
// a.js var name = 'morrain' var age = 18 exports.name = name // b.js var a = require('./a.js') console.log(a.name) // 'morrain' a.name = 'rename' console.log(a.name) // 'rename' var b = require('./a.js') console.log(b.name) // 'rename'
对比esm,cjs运行时加载引入,esm编译阶段引入:
cjs引入时加载整个模块,生成一个对象,导出对象的方法和属性;esm通过export输出代码块,import导入代码块;
cjs导入对象会被缓存,多次导入的对象互相影响;esm导入为代码块,相当于深拷贝,不互相影响;
解决缓存问题:
delete require.cache[require.resolve("./module1.js"),require.resolve("./module2.js")]
amd规范详解
异步模块加载,实例:requireJs
语法:
导出模块
// a.js
define(function(){
var add = function(x,y) {
return x + y;
};
return {
add : add
}
});
导出模块
require(['app/a', 'app/b'], function (m, b){
console.log(m.add(1,3), b);
});
cmd规范详解
整合了commonJS和AMD的导出,支持同步与异步加载,浏览器端运行,实例:seaJs
语法:
(function(self, factory) {
if (typeof module === 'object' && typeof module.exports === 'object') {
// 当前环境是 CommonJS 规范环境
module.exports = factory();
} else if (typeof define === 'function' && define.amd) {
// 当前环境是 AMD 规范环境
define(factory)
} else {
// 什么环境都不是,直接挂在全局对象上
self.umdModule = factory();
}
}(this, function() {
return function() {
return Math.random();
}
}))
esm规范详解
var firstName = 'zhao'
var lastName = 'li'
var lastName1 = 'gao'
var lastName2 = 'yuan'
export {firstName, lastName as b, lastName1, lastName2}
export default firstName
import {firstName, lastName} from './module1' // 按需导入
import * as circle from './circle' // 默认模块的导入