什么是模块化
模块化就是将一些系统功能进行拆分成独立可复用的模块。通常每个模块完成特定的功能,所有的模块组合起来成为一个整体,完成整个系统的功能。
无规范
早期 javascript 并未提供模块化的规范。开发者就通过语言特性模拟出该功能
立即执行函数
ajax.js 定义模块
;(function (ajax, $) {
var contentType = 'json'
// 定义的数据和方法放在此处,防止泄露污染全局
ajax.get = function get() {
console.log('GET')
}
ajax.post = function post() {
console.log('POST')
}
ajax.print = function () {
console.log(`contentType:${contentType}`)
$('body').css('background', 'red')
}
})(typeof exports === 'undefined' ? (this.ajax = {}) : exports, jQuery)
index.html 引入
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
<script src="./ajax.js"></script>
<script>
ajax.get() // GET
console.log(ajax.contentType); // undefined
ajax.contentType = 'text'
ajax.print() // contentType:json
</script>
通过script标签引入,将ajax模块挂载在全局对象window上。
在ajax模块中只暴露出了方法,不包括contentType,所以无法在外部获取与修改contentType,而是在window.ajax上新增的contentType属性。
对于第三方依赖需要手动引入,如上面传的第二个参数jQuery
优点:
- 数据是私有的, 外部只能通过暴露的方法操作
缺点:
- 第三方的依赖需要在定义该模块之前手动引入
- 需要的依赖过多会导致依赖模糊,不清楚依赖关系,难以维护
如上代码,通过立即执行函数(IIFE)
CommonJS 规范
Node.js 应用由模块组成,每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。每个模块内部有两个变量require 和 module。
module 对象
module.id:模块识别符,通常是带有绝对路径的模块文件名
module.filename:模块文件名,带有绝对路径。
module.loaded:返回一个布尔值。表示模块是否已经完成加载
module.parent:返回一个对象,表示调用该模块的模块
module.children:返回一个数组,表示模块要用到的其他模块
module.exports:表示模块对外输出的值
module.paths:模块的目录名称
module.paths:模块的搜索路径
导出 module
module对象表示当前模块,通过exports和module.exports对模块中的内容进行导出。
function foo(){}
const data = 'data'
// 导出方式一
module.exports = {
foo,
data
}
// 导出方式二
exports.data = data
exports.foo = foo
Module {
id: '.',
path: '..../commonjs',
exports: { foo: [Function: foo], data: 'data' },
filename: '..../module1.js',
loaded: false,
children: [],
paths: [
....,
'/node_modules'
]
}
导入 require
通过require()方法可以加载模块的exports导出的值
const m = require('./module1.js')
console.log(m.data); // data
m.foo() // Module1-foo
console.log(m); // { foo: [Function: foo], data: 'data' }
AMD 规范
AMD规范是异步模块加载,允许指定回调函数。使用需要引入工具库RequireJS.
下载 requirejs
官网:requirejs.org/
将requirejs导入项目,data-main用于加载入口文件(index.js)
<script data-main="index.js" src="./lib/require.js"></script>
定义模块
通过define()方法定义模块,define函数接受三个参数:
- 第一个参数是字符串,表示定义的模块名称,可选。如果无参默认为文件名称
- 第二个参数是字符串数组,表示定义的模块依赖的模块
- 第三个参数接受一个函数或是对象,函数参数是依赖注入的模块。在函数中通过
return一个对象暴露模块的属性和方法。
// 定义函数
define({
add:function(x,y){
return x + y
}
});
// 定义简单对象
define({
name:'jack',
age:20
});
// 具有依赖的模块
define(['./module1', './module3'], function (module1, module3) {
return {
name: module3.name,
age: module3.age,
add: module1.add,
}
})
require 导入
require:接受2个参数
- 第一个参数是字符串数组,表示依赖的模块
- 第二个参数是回调函数
// 导入模块使用
require(['./module2'],function(module2){
console.log(module2.name); // jack
console.log(module2.add(1,2)); // 3
})
CMD 规范
下载引入seajs
GITHUB:github.com/seajs/seajs…
<script src="./lib/sea.js"></script>
<script type="text/javascript">
seajs.use('./index')
</script>
使用
// module1.js
define(function (require, exports, module) {
var data = 'module1'
function print() {
console.log(data)
}
exports.print = print
})
// module2.js
define(function (require, exports, module) {
module.exports = {
msg: 'module2',
}
})
// module3.js
define(function (require, exports, module) {
//同步引入依赖模块
var module2 = require('./module2')
function print() {
console.log(module2.msg)
}
exports.print = print
})
// index.js
define(function(require){
var module1 = require('./module1')
var module3 = require('./module3')
module1.print() // module1
module3.print() // module2
});
ES Module 规范
ES Module 通过export导出,import引入模块
// 暴露一个函数
export function foo(){
console.log('foo');
}
// 暴露一个变量
export const data = [1,2]
function f1(){
console.log('f1');
}
// 暴露一个对象
export {
f1
}
// 默认暴露
export default {
name:'ES Module',
print:function(value){
console.log(value);
}
}
import { f1, foo, data } from './module1'
import module1 from './module1'
foo() // foo
f1() // f1
console.log(data) // [1, 2]
console.log(module1.name) // ES Module
module1.print('hello') // hello
使用import时,需要知道导入的变量名或函数名。除非是通过export default指定模块默认输出