前端模块化
模块化:将一些属性比较类似和行为比较类似的内容放在同一个js文件中,这个js文件就称为模块
模块的几个特点:独立性、完整性、各个模块的依赖关系
在最开始的时候,前端并没有模块的机制,代码得不到有效的妥善管理,为了使代码易于维护,有利于开发,前端圈开始制定规范,如CommonJs AMD CMD
一般情况下,我们实现模块的方式有以下四种:
1、函数
一个函数,一种功能,用函数进行封装
function func (a, b) {
return a+b;
}
function f (msg) {
console.log(msg);
}
... // 其他函数
当需要什么功能时,调用相应的函数
2、对象包装
将所有的操作都写在对象中,用对象封装
var obj = {
length : 3,
add : function (){
length++;
},
output: function () {
console.log(length);
}
... // 其他操作
}
通过obj对象调用,如:obj.add()
但是这种方式有种弊端,对象内部的属性可以被修改,如:可以通过obj.length = 4; 的方式进行修改
3、匿名函数
通过一个匿名函数,将所有的操作封装起来
var obj = (function () {
var len = 3;
function add (a, b) {
return a+b;
}
... // 其他操作
return {
add:add
...
}
})();
让该匿名函数返回一个对象,对象中包含了内部封装的所有的操作的引用,在外部使用一个变量进行接收,通过该变量来使用
4、依赖传入实参
这种方式,也是JQuery框架所使用的方式
(function (a, b) {
b(a);
})(window, function (window) {
window.jQuery = window.$ = jQuery;
function jQuery() {
}
... // 其他操作
})
也可以这样来实现,参数中传入的是一个模块,而不是将window直接传入
var module = (function (m) {
m.add = function (a, b) {
return a+b;
}
... // 其他操作
return m;
})(window.module || {})
但是上面的方式存在的缺点是依赖关系不好处理,需要按顺序加载,会阻塞页面
CommonJs规范
每一个文件都是一个模块,内部的变量都属于这个模块,不会对外暴露,也就不会污染全局变量,该规范最初是用在服务端的node的
我们所使用的webpack打包工具也是对CommonJs原生支持的
CommonJs核心思想就是通过require方法来同步加载所依赖的其他模块,然后通过exports或者module.exports来导出要暴露的接口
// moudule.js
通过module.exports或者exports,将实现的对象模块导出
module.exports = {
add:function (a, b) {
return a+b;
}
}
// index.js
用一个变量接收通过require加载到的所依赖的模块
var module1 = require('module.js');
module1.add(1, 2);
但是浏览器并不兼容CommonJs,缺少module、exports、require、globa四个环境变量,如果需要使用,需要使用工具转换
而且由于CommonJs是同步加载,所有一般都是用在服务器端,浏览器端并不适合同步加载,避免页面瘫痪(阻塞)
AMD规范
AMD规范是异步加载模块,允许指定回调函数,等模块异步加载完成后即可调用回调函数
require.js是AMD规范的实现
AMD的核心思想就是通过define来定义一个模块,然后使用require来加载一个模块。
使用时,需要使用script标签将requirejs引入
<script src="./require.js" data-main="./main.js"></script>
// main.js
// 一般情况下,是使用外部文件配置路径
require.config({
// 模块引入路径
})
// module即为js模块
require(['module'], function () {
... // 相关操作
})
CMD规范
CMD也是实现异步加载,它跟AMD的区别在于AMD依赖前置,提前加载依赖,而CMD是就近加载依赖,按需加载
哪需要,就在哪加载
sea.js就是CMD的产物,跟require.js使用有些相似
CMD的核心思想也是通过define来定义一个模块,然后使用require来加载一个模块。
使用时,也是需要使用script标签进行引入
<script src="./sea.js"></script>
<script>
seajs.use('main.js');
</script>
// main.js
通过define将module.js模块引入,通过require加载模块,哪里需要就在那里加载
define(function (require, exports, module) {
var module1 = require('module.js');
console.log(module1);
})
// module.js
通过define定义一个模块,通过exports将模块导出
define(function (require, exports, module) {
var arr = [1, 2, 3];
exports.module1 = arr;
})
ES6模块化
ES6自带模块化,可以使用import 关键字引入模块,通过export关键字导出模块,功能较之前的几个方案更为强大,也是我们所推崇的,但是由于ES6目前无法在浏览器中执行,所以,我们只能通过babel将不被支持的import编译为当前受广泛支持的require
// 引入模块
import toot form './tool.js'
// 导出模块
export class show {
constructor () {
this.age = 12;
}
showAge () {
return this.age;
}
}