1理解:
什么是模块/模块化?
将一个复杂的程序依据一定的规范封装成几个块,并组合在一起
块的内部数据/实现是私有的,只是向外部暴露一些接口(方法)与外部其他模块通信
为什么要模块化?
降低复杂度
提高解耦性
部署方便
模块化的好处
避免命名冲突
更好的分离,按需加载
更高复用性
更好维护
页面引入加载script
问题:
请求过多
依赖模糊
难以维护
2模块进化史
全局function模式 //污染全局
namespace模式 //不安全
IIFE模式
IIFE模式增强
load script
3.模块化规范
1.CommonJS
规范:
说明:http://wiki.commonjs.org/wiki/Modules/1.1
每个文件都可当作一个模块
在服务器端:模块的加载是运行时同步加载的
在浏览器端:模块需要提前编译打包处理
基本语法:
暴露模块:
module.exports = value
exports.xxx = value
问题:暴露的模块到底是什么?
exports对象 (其实,module.exports原本就是一个空的对象。)
引入模块
require(xxx) //第三方模块:xxx为包名;自定义模块:xxx为模块文件路径
实现:
服务器端实现: node.js
http://nodejs.cn/
浏览器端实现: Browserify
//node.js模块化教程
1.下载安装node.js
2.创建目录结构
/-Modules
/-modelu1.js
/-modelu2.js
/-modelu3.js
/-app.js
/-package.json
{
"name": "commonjs_node",
"version": "1.0.0"
}
3.下载第三方模块
npm install uniq
4.模块化编码
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("module3")
}
exports.arr = [2,4,5,2,3,11]
app.js
//引入第三方库uniq
let uniq = require("uniq")
//将其他模块汇集到主模块
let module1 = require('./modules/module1')
let module2 = require('./modules/module2')
let module3 = require('./modules/module3')
module1.foo() //module1
module2()//module2
module3.foo()//module3
let result = uniq(module3.arr)
console.log(result) //[11,2,3,4,5]
5.运行
node app.js
Browserify模块化使用教程
/-js
/-dist //打包生成文件的目录
/-src //源码所在目录
/-module1.js
/-module2.js
/-module3.js
/-app.js //应用主源文件
/-index.html
/-package.json
{
name:"browserify-test"
}
2.下载browserify
全局: npm install browserify -g
局部:npm install browserify --save-dev //--save运行依赖的包 -dev开发依赖的包
3.定义模块代码
4.打包处理js
browserify js/src/app.js -o js/dist/bundle.js
5.页面使用引入
<script src="js/dist/bundle.js" type="text/javascript" charset="utf-8"></script>
6.运行index.html到浏览器
AMD
规范:
说明:
Asynchronous Module Definition (异步模块定义)
http://github.com/amdjs/amdjs-api/wiki/AMD
专门用于浏览器端,模块的加载是异步的
基本语法:
定义暴露模块
//定义没有依赖的模块
define(function(){return 模块})
//定义有依赖的模块
define([‘module1’, ‘module2’],function(m1,m2){ return 模块 })
引用使用模块
require([‘module1’, ‘module2’],function(m1,m2){ 使用m1/2})
实现(浏览器端)
Require.js
http://www.requirejs.cn/
Require.js使用教程
1.下载require.js 并引入
官网 http://www.requirejs.org
https://github.com/requirejs/requirejs
将require.js导入项目js/libs/require.js
2.创建项目结构
/-js
/-lib
/-require.js
/-modules
/-alerter.js
/-dataService.js
/-main.js
/-index.html
3.定义require.js的模块代码
dataService.js:
//定义没有依赖的模块
define(function(){
let name= "dataService"
function getName(){
return name
}
//暴露模块
return {getName}
})
alerter.js:
//定义有依赖的模块
define(['dataService'],function(dataService){
let msg = "alerter.js"
function showMsg(){
console.log(msg,dataService.getName())
}
//暴露模块
return {showMsg}
})
main.js:
(function(){
requirejs.config({
//baseUrl: 'js/lib', //基本的路径
paths:{ //配置路径
dataService: './modules/dataService',
alerter: './modules/alerter'
}
})
requirejs(['alerter'], function(alerter){
alerter.showMsg()
})
})()
4.页面引入
<script src="js/libs/require.js" data-main="js/main.js" ></script>
3.CMD(已经卖给国外)
规范:
说明:
https://github.com/seajs/seajs/issues/242
专门用于浏览器端,模块的加载是异步的
模块在使用时才会加载执行
基本语法:
定义暴露模块:
//定义没有依赖的模块
define(function(require, exports, module){
exports.xxx = value
module.exports = value
)
//定义有依赖的模块
define(function(require, exports, module){
//引入依赖模块(同步)
var module2 = require(’./module’)
//引入依赖模块(异步)
require.async(’./module3’,function(m3){
})
//暴露模块
exports.xxx = value
)
引入使用模块
define(function(require){
var m1=require(’./module1’)
m1.show()
})
实现:
sea.js
http://www.zhangxinxu.com/sp/seajs
4ES6
规范:
说明:
http://es6runayifeng.com/#docs/module
依赖模块需要编译打包处理
语法:
导出模块:export
引入模块:import
实现(浏览器端):
使用babel将es6编译为es5代码
使用browserify编译打包js
ES6 Bable-Browserify使用教程
1.定义package.json文件
2.安装babel-cli, babel-preset-es2015, 和browserify //cli :command line interface命令行接口
npm install babel-cli browserify -g //全局安装babel
npm install babel-preset-es2015 --save-dev //当前项目安装
preset 预设(将es6转换成es5的所有插件打包)
3.定义.babelrc文件 (rc //run control //运行时控制文件)
{
“presets”:[“es2015”]
}
4.编码
js/src/module1.js:
//暴露模块 分别暴露
export function foo(){
console.log(“foo() module1”)
}
export function bar(){
console.log("bar() module1")
}
export let arr = [1,4,"bc"]
js/src/module2.js:
//统一暴露
function fun(){
console.log("fun() module2")
}
function fun2(){
console.log("fun2() module2")
}
export {fun,fun2}
js/src/module3.js:
//默认暴露 可以暴露任意数据类型,暴露什么数据接收到的就是什么数据
//export default value
export default{
msg:"默认暴露",
foo(){
console.log(this.msg)
}
}
js/src/main.js:
//引入其他的模块
//语法 import xxx form '路径'
import {foo, bar} from './module1' //必须用对象结构赋值的形式
import {fun, fun2} from './module2'
import module3 from './module3' //默认暴露直接用变量接收
foo()
bar()
fun()
fun2()
module3.foo()
5.编译
使用babel将es6编译为es5代码(但包含CommonJS语法):babel js/src -d js/lib
使用browserify 编译js :browserify js/lib/main.js -o js/dist/bundle.js
6.页面使用引入
<script src="js/dist/bundle.js" type="text/javascript" charset="utf-8"></script>
运行到浏览器;