简介
模块化的好处:
- 避免命名冲突
- 更好的分离,按需加载
- 更高复用性
- 高可维护性
产生的问题:
- 请求过多
- 依赖模糊
- 难以维护
modular
1. 全局function模式
let msg = "feidu";
function f1() {
console.log("01-f1: " + msg);
}
<script src="./01.js"></script>
<script>
f1(); // 01-f1: feidu
// 数据可以修改,不安全
msg = "jianrong";
f1(); // 01-f1: jianrong
</script>
2. namespace模式:简单对象封装
let obj = {
msg: "feidu",
f1() {
console.log("01-f1: " + this.msg);
},
};
<script src="./01.js"></script>
<script>
obj.f1(); // 01-f1: feidu
// 数据还是可以修改
obj.msg = "jianrong";
obj.f1(); // 01-f1: jianrong
</script>
3. IIFE模式:匿名函数自调用
(function (window) {
let msg = "feidu";
function f1() {
console.log("01-f1: " + msg);
}
window.m = { f1 };
})(window);
<script src="./01.js"></script>
<script>
m.f1(); // 01-f1: feidu
// 此时无法访问数据
</script>
4. IIFE增强
(function (window) {
let msg = "feidu";
function f1() {
console.log("01-f1: " + msg);
}
window.f = f1;
})(window);
<script src="./01.js"></script>
<script>
f(); // 01-f1: feidu
// 此时无法访问数据
</script>
CommonJS
- 每一个JS文件都可以当做一个模块
- 在服务器端:模块的加载是运行时同步加载的
- 在浏览器端:模块需要提前编译打包处理
导出模块
module.exports = value
exports.xxx = value
引入模块
let m1 = require("./modules/module1");
服务器端实现:Node.js
let m1 = require("./modules/module1");
let m2 = require("./modules/module2");
let m3 = require("./modules/module3");
m1.f1(); // module1
m2(); // module2
m3.f1(); // module3
module.exports = {
msg: "module1",
f1() {
console.log(this.msg);
},
};
module.exports = function () {
console.log("module2");
};
exports.f1 = function () {
console.log("module3");
};
浏览器端实现:Browserify
<!-- 模块的编写方式同上 -->
<!-- 直接引入的话浏览器不认识require方法 -->
<!-- <script src="./js/src/app.js"></script> -->
<!--
使用命令编译:npx browserify JS模块化/js/src/app.js -o JS模块化/js/dist/bundle.js
然后在页面上引入编译的js文件
-->
<script src="./js/dist/bundle.js"></script>
AMD
- 专门用于浏览器端,模块的加载是异步的
定义没有依赖的模块
define(function() {
return 模块
})
定义有依赖的模块
define([module1, module2], function(m1, m2) {
return 模块
})
引入使用模块
require([module1, module2], function(m1, m2) {
使用 m1, m2
})
实例
define(function () {
let name = "dataService";
function getName() {
return name;
}
return { getName };
});
define(["dataService"], function (dataService) {
let msg = "alterer";
function showMsg() {
console.log(msg, dataService.getName());
}
return { showMsg };
});
(function () {
requirejs.config({
baseUrl: "js/modules",
paths: {
// 配置模块名字与路径的对应,文件名不加 .js
// 如果不配置baseUrl,此时的路径相对于app.js
// dataService: "./modules/dataService",
// alterer: "./modules/alterer",
// 如果配置baseUrl,路径相对于根目录
dataService: "dataService",
alterer: "alterer",
},
});
requirejs(["alerter"], function (alterer) {
alterer.showMsg();
});
})();
<!-- 绑定主模块和requirejs -->
<script data-main="./js/app.js" src="./js/libs/require.js"></script>
使用第三方模块
requirejs.config({
baseUrl: "js/modules",
paths: {
// 要注意模块是否支持AMD 以及模块名称的问题
jquery: "jquery-1.10.1",
angular: "angular"
},
shim: {
angular: {
exports: "angular",
},
},
});
CMD
- 专门用于浏览器端,模块的加载是异步的
- 模块使用时才会加载执行
定义没有依赖的模块
define(function(require, exports, module) {
exports.xxx = value
module.exports = value
})
定义有依赖的模块
define(function(require, exports, module) {
同步引入依赖模块
let module2 = require('./module2)
异步引入依赖模块
require.async('./module3', function(m3) {
})
exports.xxx = value
})
引入使用模块
define(function (require) {
let m2 = require('./module2)
let m4 = require('./module4)
m2.show()
m4.show()
})
<script src="./js/libs/sea.js"></script>
<script>
seajs.use('./js/modules/main.js')
</script>
ES6
参考:模块化 章节
https://blog.csdn.net/Alice_Lee_Lee/article/details/120845338
补充 babel 说明:
- 配置文件:.babelrc 这是一个json文件,配置内容可以参考官网
- babel 将代码转换为 ES5 的,但是代码中仍旧包含 Node中require 的语法