常见的模块化规范有:CommonJS、AMD、CMD、ES6
一、CommonJS
1).实现
服务器端:Node.js
浏览器端:Browserify
2)基本语法
定义暴露模块:exports
exports.xxx = value;
module.exports = value;
引入模块:require
var module = require(‘模块名/模块相对路径’)
3)引入模块发生什么时候?
Node:运行时,动态同步引入;
Browserify:在运行前对模块化进行编译打包的处理(已经将依赖的模块包含进来了),运行的是打包生成的js(浏览器不认识require),运行时不存在需要再从远程引入依赖模块。
4)代码实现
目录结构:
-modules
--module1.js
--module2.js
--module3.js
-node_modules
-app.js
-package.json
module1.js
//module.exports = value 暴露一个对象
module.exports = {
msg : 'module1',
foo(){
console.log(this.msg);
}
}
module2.js
//暴露一个函数 module.exports = function(){}
module.exports = function(){
console.log('module2');
}
//不能无限添加,后面的代码会覆盖前面的代码
module3.js
//exports.xxx = value
//可以无限添加
exports.foo = function(){
console.log("foo() module3");
};
exports.bar = function(){
console.log("bar() module3");
}
exports.arr = [2,3,2,4,5,8,7,1];
app.js
//将其他模块汇集到主模块中
1. 定义暴露模块:
module.exports = value;
exports.xxx = value;
2. 引入模块:
var module = require(模块名或模块路径);
//第三方库要放在最上方
let uniq = require('uniq');
let module1 = require('./modules/module1');
let module2 = require('./modules/module2');
let module3 = require('./modules/module3');
module1.foo();
module2();
module3.foo();
module3.bar();
let result = uniq(module3.arr);
console.log(result);
package.json
{
"name": "commonjs_node",
"version": "1.0.0",
"dependencies": {
"uniq": "^1.0.1"
}
}
浏览器端:CommonJS-Browserify
Index.html
<script type="text/javascript" src="js/src/app.js"></script>
浏览器不识别require,所以需要将js打包
二、AMD
1)实现
浏览器端:require.js(requireJS)
2)基本语法
定义暴露模块:
define([依赖模块名],function(){
return 模块
})
引入模块:
require([‘模块1’,’模块2’],function(m1,m2){
//使用m1与m2
})
配置
require.config({
//基本路径
baseUrl:’src/’,
//映射:模块标识名:路径
paths:{
//自定义模块
‘a’:’modules/a’,
‘b’:’modules/b’,
//第三方库
‘jquery’:’libs/jquery-1.10.1’
}
})
3)代码实现
dataService.js
//无依赖
define(function(){
let msg = "atguigu.com"
function getMsg(){
return msg.toUpperCase();
}
return {getMsg}
})
Alerter.js
//有依赖
define([
'dataService',
'jquery'
], function(dataService, \$) {
let name = "Tom2";
function showMsg(){
$('body').css('background','gray');
alert(dataService.getMsg()+","+name);
}
return {showMsg}
});
Main.js
(function(){
//配置
require.config({
//基本路径
baseUrl : "js/",
//模块标识与模块路径映射
paths:{
//第三方库
"jquery":"libs/jquery-1.10.1",
//自定义模块
"alerter":"modules/alerter",
"dataService":"modules/dataService"
}
})
//引入使用模块
require(['alerter'],function(alerter){
alerter.showMsg()
})
})()
Test.html
<script type="text/javascript" src="js/libs/require.js" data-main="js/main.js"></script>
data-main属性的作用是,指定网页程序的主模块。在上例中,就是js目录下面的main.js,这个文件会第一个被require.js加载。由于require.js默认的文件后缀名是js,所以可以把main.js简写成main。
三、CMD
1)实现
浏览器端:sea.js(seaJS)
2)基本语法
定义暴露模块:
define(function(require,module,exports){
通过require()引入依赖模块
通过module/exports来暴露模块
exports.xxx = value
})
使用模块:
seajs.user([‘模块1’],[‘模块2’])
3)代码实现
Module1.js
define(function(require,exports,module){
//内部变量数据
var data = "atguigu.com";
function show(){
console.log('module1 show()'+data);
}
//向外暴露
exports.show = show;
});
Module2.js
define(function(require,exports,module){
module.exports = {
msg : 'I WILL BACK'
}
})
Module3.js
define(function(require,exports,module){
const API_KEY = "abc123";
exports.API_KEY = API_KEY;
});
Module4.js
define(function(require,exports,module){
//引入依赖模块(同步)
var module2 = require('./module2');
function show(){
console.log("module4 show() "+module2.msg)
}
exports.show = show;
//引入依赖模块(异步)
require.async('./module3',function(m3){
console.log('异步引入依赖模块3'+m3.API_KEY);
})
});
Main.js
define(function(require){
//不需要暴露时,形参只需要require即可
var m1 = require('./module1');
var m4 = require('./module4');
m1.show();
m4.show();
})
Index.html
<!--
使用seajs:
1.引入sea.js库
2.如何定义导出模块:
define() exports module.exports
3.如何依赖模块:require()
4.如何使用模块:seajs.use()
-->
<script type='text/javascript' src="js/libs/sea.js"></script>
<script type='text/javascript'>
seajs.use('./js/modules/main');
</script>
四、ES6
1)ES6内置了模块化的实现
2)基本语法
定义暴露模块:export
默认暴露(暴露一个数据):export default 对象
一般暴露(暴露多个数据):export {对象,对象}
引入使用模块 import
- 引入default 模块
import xxx from ‘模块路径/模块名’
- 引入一般模块:
import {a,b} from ‘模块路径/模块名’
import * as module1 from ‘模块路径/模块名’
3)问题
所有浏览器还不能直接识别ES6模块化的语法
4)解决
使用webpack编译打包
5)代码实现
.babelrc
{
"presets":["es2015"]
}
module1.js
//暴露模块 分别暴露
export function foo(){
console.log('foo() module1');
}
export function bar(){
console.log('bar() module1');
}
module2.js
//统一暴露
function fun(){
console.log('fun() module2');
}
function fun2(){
console.log('fun2() module2');
}
export {fun,fun2};
module3.js
//默认暴露 可以暴露0,或者任意数据类型,
//暴露什么数据接收到的就是什么数据
//export default value;
export default () => {
console.log('我是默认暴露的箭头函数');
}
Main.js
//引入其他的模块
//语法:import xxx from '路径'
import $ from 'jquery'
import {foo,bar} from './module1';
import {fun,fun2} from './module2';
import module3 from './module3';
$('body').css('background','red');
foo();
bar();
fun();
fun2();
module3();
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ES6</title>
</head>
<body>
<!--<script type='text/javascript' src='js/src/main.js'></script>-->
<script type='text/javascript' src='js/lib/bundle.js'></script>
</body>
</html>