一、什么是模块 / 模块化
在学习js模块化之前,我们要知道什么是模块 / 模块化。
模块/模块化:将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并进行组合在一起。块的内部数据(实现)是私有的, 只是向外部暴露一些接口(方法)与外部其它模块通信。
二、为什么要使用模块化
网站正在变成网络应用程序,代码复杂度随着网站的扩大而增加, 开发者需要高度解耦的JS文件/模块管理网页的业务逻辑,在部署时也需要优化代码,所以Javascript模块化编程,已经成为一个迫切的需求。
三、模块化的好处
- 避免命名冲突(减少命名空间污染);
- 更好的分离, 按需加载;
- 更高复用性;
- 高可维护性。
四、模块化规范—CommonJS
1、说明
- 每个文件都可当作一个模块;
- 在服务器端: 模块的加载是运行时同步加载的;
- 在浏览器端: 模块需要提前编译打包处理。
2、基本语法
a. 暴露模块
方法一:module.exports = value
方法二:exports.xxx = value
b. 引入模块
require(xxx)
第三方模块:xxx为模块名
自定义模块: xxx为模块文件路径
3、实现
a. 服务器端实现(Node.js)
(1)、创建项目结构
(2)、定义模块代码
module1.js
//暴露一个对象 module.exports=value
module.exports={
msg:"module1",
foo(){
console.log("foo()",this.msg);
}
};
module2.js
//暴露一个函数 module.exports=function(){}
module.exports=function () {
console.log("modile2");
};
module3.js
//exports.xxx=value;
exports.bar=function () {
console.log("bar", "module3");
};
app.js
let module1=require("./modules/module1");
let module2=require("./modules/module2");
let module3=require("./modules/module3");
module1.foo();
module2();
module3.bar();
(3)、安装node.js,并通过node运行app.js
命令: node app.js
工具: 右键–>运行
运行结果
b. 浏览器端实现(Browserify)
(1)、基于以上,下载browserify
全局:
npm install browserify -g
局部:npm install browserify --save-dev
(2)、打包处理js
browserify js/src/app.js -o js/dist/bundle.js
(3)、创建index.html
,在页面中引入bundle.js
<script type="text/javascript" src="js/dist/bundle.js"></script>
五、模块化规范—AMD
1、说明
- 专门用于浏览器端
- 模块的加载是异步的
2、基本语法
a. 暴露模块
(1)、定义没有依赖的模块
define(function(){
return 模块
})
(2)、定义有依赖的模块
define(['module1', 'module2'], function(m1, m2){
return 模块
})
b. 引入模块
require(['module1', 'module2'], function(m1, m2){
使用m1/m2
})
3、实现(浏览器端)
a. 不使用AMD规范
(1)、创建项目结构
(2)、定义模块代码
module1.js
(function (window) {
let msg="module1";
function showMsg(){
console.log(msg);
}
window.showMsg=showMsg;
})(window);
module2.js
(function (window,showMsg) {
data="module2";
function getData() {
console.log(data);
showMsg();
}
window.getData=getData;
})(window,showMsg);
app.js
(function (getData) {
getData();
})(getData);
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>01_NoAMD</title>
</head>
<body>
<script src="js/module1.js"></script>
<script src="js/module2.js"></script>
<script src="js/app.js"></script>
</body>
</html>
(3)、引起的问题
页面中加入了多个js,加载页面时,请求过多;module2.js
依赖module1.js
,所以module1.js
必须放在module2.js
的前面,但在实际开发中,这种依赖关系模糊,难以维护。
b. AMD规范(Require.js)
(1)、创建项目结构
(2)、定义require.js的模块代码
module1.js
define(function () {
let msg="require_module1";
function showMsg(){
console.log(msg);
}
return {
showMsg};
});
module2.js
define(function () {
let msg="require_module1";
function showMsg(){
console.log(msg);
}
return {
showMsg};
});
app.js
(function () {
requirejs.config({
baseURL:"js/",
paths:{
module1:"./module/module1",
module2:"./module/module2",
jquery:"./lib/jquery-1.10.1"
}
});
requirejs(['module2','jquery'],function (module2,$) {
$("body").css("background","deeppink");
module2.getData();
});
// requirejs(['module2'],function (module2,) {
// module2.getData();
// });
})();
(3)、创建index.html
,下载require.js
, 并在.html
文件中引入
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script data-main="js/app.js" src="js/lib/require.js"></script>
</body>
</html>
六、模块化规范—CMD
1、说明
- 专门用于浏览器端, 模块的加载是异步的
- 模块使用时才会加载执行
2、基本语法
a. 暴露模块
(1)、定义没有依赖的模块
define(function(require, exports, module){
exports.xxx = value
module.exports = value
})
(2)、定义有依赖的模块
define(function(require, exports, module){
//引入依赖模块(同步)
var module2 = require('./module2')
//引入依赖模块(异步)
require.async('./module3', function (m3) {
})
//暴露模块
exports.xxx = value
})
b. 引入模块
define(function (require) {
var m1 = require('./module1')
var m4 = require('./module4')
m1.show()
m4.show()
})
3、实现(浏览器端)
(1)、创建项目结构
(2)、定义模块代码
module1.js
define(function (require,exports,modules) {
let msg="module1";
function foo() {
console.log(msg);
}
modules.exports={
foo};
});
module2.js
define(function (require,exports,module) {
let data="module2";
function bar() {
console.log(data);
}
exports.bar=bar;
});
module3.js
define(function (require,exports,module) {
let data="module3";
function fun() {
console.log(data);
}
module.exports={
fun}
});
module4.js
define(function (require,exports,module) {
let msg="module4";
let module2=require("./module2");
module2.bar();
require.async("./module3",function (module3) {
module3.fun();
});
function showMsg() {
console.log(msg);
}
exports.showMsg=showMsg;
});
app.js
define(function (require) {
let m1=require("./modules/module1");
let m4=require("./modules/module4");
m1.foo();
m4.showMsg();
});
(3)、创建index.html
,下载sea.js
, 并在.html
文件中引入
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>05_CMD_SeaJS</title>
</head>
<body>
<script src="js/libs/sea.js"></script>
<script>
seajs.use("./js/app.js");
</script>
</body>
</html>
七、模块化规范—ES6
1、说明
- 依赖模块需要编译打包处理
2、基本语法
a. 暴露模块
暴露模块: export
b. 引入模块
引入模块: import
3、实现(浏览器端)
(1)、创建项目结构
(2)、定义package.json文件
{
“name” : “es6-babel-browserify”,
“version” : “1.0.0”
}
(3)、安装babel-cli, babel-preset-es2015和browserify
npm install babel-cli browserify -g
npm install babel-preset-es2015 --save-dev
说明:cli:command line interface 命令行接口;
preset 预设(将es6转换成es5的所有插件打包)。
(4)、定义 .babelrc 文件
{
“presets”: [“es2015”]
}
(5)、定义模块代码
module1.js
export function fun(){
console.log("fun() module1");
}
export function fun2() {
console.log("fun2() module2");
}
module2.js
function foo() {
console.log("foo() module2");
}
function bar() {
console.log("bar() module2");
}
export {
foo,
bar
}
module3.js
export default function () {
console.log("默认暴露");
}
app.js
// import $ from "jquery";
import {
fun,fun2} from "./module1";
import {
foo,bar} from "./module2";
import module3 from "./module3";
// $("body").css("background","green");
fun();
fun2();
foo();
bar();
module3();
(5)、编译
使用Babel将ES6编译为ES5代码(但包含CommonJS语法) :
babel js/src -d js/lib
使用Browserify编译js :
browserify js/lib/app.js -o js/lib/bundle.js
(6)、创建index.html
, 在.html
文件中引入编译后的bundle.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>06_ES6_ Babel _ Browderify </title>
</head>
<body>
<script src="js/dist/bundel.js"></script>
</body>
</html>
(7)、引入第三方模块(jQuery)
下载jQuery模块:
npm install jquery@1 --save
在app.js中引入并使用
import $ from 'jquery'
$('body').css('background', 'red')