1.什么是模块
- 将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并进行组合在一起。
- 块的内部数据与实现是私有的, 只是向外部暴露一些接口(方法)与外部其它模块通信。
2.前端模块化进程
- 函数形式
- 命名空间,简单对象封装
let myModule = {
data: 'www.baidu.com',
foo() {
console.log(`foo() ${this.data}`)
},
bar() {
console.log(`bar() ${this.data}`)
}
}
myModule.data = 'other data' //能直接修改模块内部的数据
myModule.foo() // foo() other data
- 立即执行函数
将数据和行为封装到一个函数内部, 通过给window添加属性来向外暴露接口。 - 立即执行函数模式增强,引入依赖。如下代码
// module.js文件
(function(window, $) {
let data = 'www.baidu.com'
//操作数据的函数
function foo() {
//用于暴露有函数
console.log(`foo() ${data}`)
$('body').css('background', 'red')
}
function bar() {
//用于暴露有函数
console.log(`bar() ${data}`)
otherFun() //内部调用
}
function otherFun() {
//内部私有的函数
console.log('otherFun()')
}
//暴露行为
window.myModule = { foo, bar }
})(window, jQuery)
// index.html文件
<!-- 引入的js必须有一定顺序 -->
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="module.js"></script>
<script type="text/javascript">
myModule.foo()
</script>
3.模块化的好处
- 避免命名冲突(减少命名空间污染)
- 更好的分离, 按需加载
- 更高复用性
- 高可维护性
4.模块化规范
-
CommonJS
- 概述:
1.据CommonJs规范规定每一个Js文件都可以看作一个模块,其内部定义的变量是属于这个模块的,不会对外暴露,也就是说不会污染全局变量。该规范最初用在服务器端的node环境中。
2.CommonJS采用同步加载不同模块文件,适用于服务器端的。因为模块文件都存放在服务器的各个硬盘上,读取加载时间快,适合服务器端,不适应浏览器。
3.浏览器不兼容CommonJs,原因是浏览器缺少module
、exports
、require
、global
四个环境变量。如要使用需要工具转换。在浏览器中运行的话,先使用browserify
或者webpack
工具打包编译。 - 模块加载机制
CommonJS模块的加载机制是,输入的是被输出的值的拷贝。也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。不是动态加载的。 - 语法:
1.暴露接口方式
module.exports = value;
exports.XXX = value;
(上述两种方式,exports是一个对象,被暴露出去,供其他文件使用。第一种方式:exports被赋予新值暴露。第二种,是在对象上挂载属性,然后暴露出去)
在 Node.js 模块里,真正控制模块导出的是 module.exports,exports 只是 module.exports 决定导出一个对象时的一个快捷方式,假如 module.exports 导出其它类型的数据,比如字符串、数值、函数等等,则 exports 的存在没有意义
2.引入模块
require('XXX');
如果是第三方模块,xxx为模块名;如果是自定义模块,xxx为模块文件相对路径。
- 概述:
-
AMD(异步模块定义,Asynchronous Module Definition),适用于浏览器环境
-
是什么:
1.AMD规范则是异步加载模块,允许指定回调函数。等模块异步加载完成后即可调用回调函数。
2.AMD得意的产出就是require.js
。 require官网。
3.AMD的核心思想就是通过define
来定义一个模块,然后使用require
来加载一个模块。
4.AMD规范的使用依赖于require.js 。 -
怎么用
AMD设计出一个简洁的写模块API:
define(id?, dependencies?, factory);
id
: 模块标识,可以省略。一般用于库的暴露。如:jquery
dependencies
: 所依赖的模块,可以省略。
factory
: 模块的实现,或者一个JavaScript对象。
-
下面一个小例子:
目录结构
index.html
<!-- 引入require.js文件 并指定js主文件入口 -->
<!-- (实际上除了require.js,其它文件模块都不再使用script标签引入,可以在demo.js中注明模块路径) -->
<script src="./js/require.js" data-main="./demo.js"></script>
module1.js
var counter = 0;
function computeCounter () {
counter++;
console.log(counter);
console.log('m1-amd');
}
define(function() {
'use strict';
return {counter, computeCounter}; // 暴露该模块
});
module2.js
define(['m1', 'jquery'], function(m1, $) {
'use strict';
function getM2Name() {
m1.computeCounter();
console.log(m1.counter);
console.log('m2-amd')
console.log('$==', $);
}
return getM2Name;// 暴露该模块
});
demo.js
(function () {
require.config({
baseUrl: './',
paths: {
// 模块标识名:路径(路径的出发点在根目录下面哦!!!module1后面不能有.js)
m1: 'module/module1', // m1,模块名。m2模块依赖于m1模块
m2: 'module/module2',
/**
* m2模块依赖于第三方模块,
*注意“jquery”是固定的,不能写“jQuery”或其它。这里只能写jquery(v1.7以上支持AMD)
*/
jquery: 'js/jquery'
}
})
require(['m2'], function (m2) {
console.log(m2);
m2();
})
})()
-
CMD规范(Common Module Definition,通用模块定义)。
SeaJS
就是遵循的这个规范。-
是什么?
CMD规范专门用于浏览器端,模块的加载是异步的,模块使用时才会加载执行。 -
怎么用?
CMD的核心思想就是通过define
来定义一个模块,然后使用require
来加载一个模块。
-
index.html
<script src="./js/sea.js"></script>
<script>
seajs.use('./demo.js');
</script>
module1.js
define(function (require, exports, module) {
var data = 'm1';
function showM1() {
return 'module1 show() ' + data;
}
exports.showM1 = showM1;
})
module3.js
define(function (require, exports, module) {
var data = 'm3';
function showM3() {
console.log('module3 show() ' + data);
}
exports.showM3 = showM3;
})
module2.js
define(function (require, exports, module) {
var data = 'm2';
// 异步加载模块
require.async('./module1', function (m1) {
console.log('async====', m1.showM1());
})
var m3 = require('./module3');
m3.showM3();
function showM2() {
console.log('module2 show() ' + data);
}
exports.showM2 = showM2;
})
demo.js
define(function (require, exports, module) {
var demo = require('./module/module2');
demo.showM2();
})
- es6的
import
由于ES6目前无法在浏览器中执行,所以,我们只能通过babel将不被支持的import编译为当前受到广泛支持的require
。