模块化历史
- 早期浏览器(没有JS引擎)只能执行一小段的js,没用模块化的概念
- 有了JS引擎之后,所有文件放在一个文件太大太复杂
- 最早的模块化是 inde.html引入index.js index2.html引入index2.js (这就会出现一个问题:如果有个bar函数,index和index2都需要用到,那么代码就变得冗余)
- 为了解决这个问题,我们抽离出一个common.JS,把公共的代码放如其中,并且在html中引入先引入common.js再引入其他的JS
-(这样又出现了新问题:common.js有个方法bar,五个页面需要这个方法,两个页面不需要这个方法,所以就会引用很多无用的东西,) - 为了解决这个问题,我们把每个功能模块都抽离出来作为一个js文件,在页面中需要使用哪个JS就去引用
- (这样又出现了新问题:模块多, 那么js的引用变得非常复杂,引用的JS顺序一定要正确,且模块多污染了全局作用域(变量不能重名覆盖))
- es5的解决方法:使用闭包(立即执行函数)
// a.js
const fn1 = (function() {
// code...
return {
a: function() { *** },
b: function() { *** },
}
}());
// b.js
const fn2 = (function(fn1) {
// 可以使用 fn1 里面的方法a,b
// code...
return {
c: function() { *** },
d: function() { *** },
}
}(fn1));
// c.js
const b = (function(fn1, fn2) {
// 可以使用 fn1, fn2 里面的方法a, b, c, d
// code...
return { // 就算只有一个方法也要返回一个对象,因为模块是要易扩展的
e: function() { *** },
f: function() { *** },
}
}(fn1, fn2));
es5的方式解决变量污染全局,且模块独立且可以互相依赖了,但是js的引入顺序变得复杂
所以,模块化解决的问题就是 **加载顺序,污染全局**
commonJS
- require() 必须是相对路径,绝对路径是找node_modules中的文件
- 依赖延迟声明( commonJS )
- 优点:某些时候可以提高效率
- 缺点:无法在一开始确定模块依赖关系(比较模糊)
// 实现方式(简化版)
;(function(module) {
module.exports = {};
const exports = module.exports;
// node...
return module.exports; // 导出的是module.exports
})();
ES6模块化
- 导入也必须是相对路径
- 依赖预声明(引入模块必须在最顶部)
- 优点:在一开始可以确定模块依赖关系
- 缺点:某些时候效率较低
export const a = 1; // 基本导出
const b = 2;
const c = 3;
export { b, c }; // 具名导出
export default 4; // 默认导出 相当于 export default const default = 4;
import d, { a, b, c as e } from './a.js';
// 导入的变量名要和导出的变量名相同,且要在具名符号{}内
// as 可以重新命名导入变量名, 如 c as e
// default是一个关键字,不能使用,所以放在具名符号{}外, 用 as 关键字可以在具名符号内 import { a, b, c, default as d } from './a.js'
console.log(a, b, e, d); // 1, 2, 3, 4
import * as obj from './a.js'; // 导出全部,并且重命名
console.log(obj);