一、什么是模块化?
1.1 定义
- 将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并进行组合在一起
- 块的内部数据/实现是私有的, 只是向外部暴露一些接口(方法)与外部其它模块通信
1.2 模块化的进化过程
1.2.1 全局function模式
* 全局函数模式: 将不同的功能封装成不同的全局函数
* 问题: Global被污染了, 很容易引起命名冲突
*/
function foo() {
console.log('foo()')
}
function bar() {
console.log('bar()')
}
问题: 污染全局命名空间, 容易引起命名冲突/数据不安全
1.2.2 namespace模式
/**
* namespace模式: 简单对象封装
* 作用: 减少了全局变量
* 问题: 不安全(数据不是私有的, 外部可以直接修改)
*/
let myModule = {
data: 'Jerry',
foo() {
console.log(`foo() ${this.data}`)
},
bar() {
console.log(`bar() ${this.data}`)
}
}
- 减少了Global上的变量数目
- 本质是对象,一点都不安全
1.2.3 IIFE模式
/**
* IIFE模式: 匿名函数自调用(闭包)
* IIFE : immediately-invoked function expression(立即调用函数表达式)
* 作用: 数据是私有的, 外部只能通过暴露的方法操作
* 问题: 如果当前这个模块依赖另一个模块怎么办?
*/
(function (window) {
//数据
let data = 'Jerry'
//操作数据的函数
function foo() { //用于暴露有函数
console.log(`foo() ${data}`)
}
function bar() {//用于暴露有函数
console.log(`bar() ${data}`)
otherFun() //内部调用
}
function otherFun() { //内部私有的函数
console.log('otherFun()')
}
//暴露行为
window.myModule = {foo, bar}
})(window)
IIFE模式增强:引入依赖
(function (window, $) {
//数据
let data = 'Jerry'
//操作数据的函数
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)
- IIFE : 立即调用函数表达式--->匿名函数自调用
- 编码: 将数据和行为封装到一个函数内部, 通过给window添加属性来向外暴露接口
- 引入依赖: 通过函数形参来引入依赖模块
1.3 模块化的好处
- 避免命名冲突(减少命名空间污染)
- 更好的分离,按需加载
- 更高复用性
- 高可维护性
<body>
<!--
1. 一个页面需要引入多个js文件
2. 问题:
1). 请求过多
2). 依赖模糊
3). 难以维护
3. 这些问题可以通过现代模块化编码和项目构建来解决
-->
<script type="text/javascript" src="module1.js"></script>
<script type="text/javascript" src="module2.js"></script>
<script type="text/javascript" src="module4.js"></script>
<script type="text/javascript" src="module3.js"></script>
<script type="text/javascript" src="../04_IIFE模式增强/jquery-1.10.1.js"></script>
<script type="text/javascript" src="../04_IIFE模式增强/test4.js"></script>
<script type="text/javascript">
module.foo()
</script>
</body>
二、模块化规范
2.1 CommonJS
Node.js: 服务器端
Browserify : 浏览器端 也称为js的打包工具(CommonJs 浏览器端打包工具 )
// 基本语法:
// 定义暴露模块 : exports
exports.xxx = value
module.exports = value
// 引入模块 : require
var module = require('模块名/模块相对路径')
引入模块发生在什么时候?
- Node : 运行时, 动态同步引入
- Browserify : 在运行前对模块进行编译/转译/打包的处理(已经将依赖的模块包含进来了), 运行的是打包生成的js, 运行时不存在需要再从远程引入依赖模块
2.1.1 CommonJS-Node
代码示例:
module1.js 使用module.exports = value向外暴露一个对象
/**
* 使用module.exports = value向外暴露一个对象
*/
"use strict"
module.exports = {
foo() {
console.log('moudle1 foo()')
}
}
module2.js 使用module.exports = value向外暴露一个对象
/**
* 使用module.exports = value向外暴露一个函数
*/
module.exports = function () {
console.log('module2()')
}
module3.js 使用exports.xxx = value向外暴露多个对象
/**
* 使用exports.xxx = value向外暴露多个对象
*/
"use strict"
exports.foo = function () {
console.log('module3 foo()')
}
exports.bar = function () {
console.log('module3 bar()')
}
使用时,用 require() 语法导入
/**
1. 定义暴露模块:
module.exports = value;
exports.xxx = value;
2. 引入模块:
var module = require(模块名或模块路径);
*/
"use strict"
//引用模块
let module1 = require('./modules/module1')
let module2 = require('./modules/module2')
let module3 = require('./modules/module3')
let uniq = require('uniq')
let fs = require('fs')
//使用模块
module1.foo()
module2()
module3.foo()
module3.bar()
console.log(uniq([1, 3, 1, 4, 3]))
fs.readFile('app.js', function (error, data) {
console.log(data.toString())
})
2.1.2 CommonJS-Browserify
下载 browserify
* 全局: npm install browserify -g
* 局部: npm install browserify --save-dev
打包处理js:
browserify js/src/app.js -o js/dist/bundle.js
页面使用引入:
<script type="text/javascript" src="js/dist/bundle.js"></script>
2.2 AMD - RequireJS
说明: 专门用于浏览器端,模块的加载是异步的 AMD · amdjs/amdjs-api Wiki · GitHub
基本语法:
定义暴露模块:
// 定义没有依赖的模块
define(function () {
let msg = 'atguigu.com'
function getMsg() {
return msg.toUpperCase()
}
return {getMsg}
})
// 定义有依赖的模块
define(['dataService', 'jquery'], function (dataService, $) {
let name = 'Tom2'
function showMsg() {
$('body').css('background', 'gray')
alert(dataService.getMsg() + ', ' + name)
}
return {showMsg}
})
引入使用模块:
//引入使用模块
requirejs( ['alerter'], function(alerter) {
alerter.showMsg()
})
举例说明:alerter.js 依赖 dataService.js 和 jquery模块,可以在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: {
//自定义模块
'alerter': 'modules/alerter',
'dataService': 'modules/dataService',
//库模块
'jquery': 'libs/jquery-1.10.1',
'angular': 'libs/angular'
},
//配置不兼容AMD的模块
shim: {
angular: {
exports: 'angular'
}
}
})
//引入模块使用
require(['alerter', 'angular'], function (alerter, angular) {
alerter.showMsg()
console.log(angular);
})
})()
在html页面中引入即可:
<!DOCTYPE html>
<html>
<head>
<title>Modular Demo 2</title>
</head>
<body>
<script type="text/javascript" src="js/libs/require.js" data-main="js/main.js"></script>
</body>
</html>
关于 require.js 的详细用法可以参考:
Javascript模块化编程(三):require.js的用法 - 阮一峰的网络日志
2.3 CMD - SeaJS
首先需要引入 sea.js的库
<script type="text/javascript" src="js/libs/sea.js"></script>
定义导出模块 define() exports module.exports
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
})
引入依赖模块 require()
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) {
var m1 = require('./module1')
var m4 = require('./module4')
m1.show()
m4.show()
})
使用模块 seajs.use()
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Title</title>
</head>
<body>
<!--
使用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>
</body>
</html>
2.4 ES6 模块化
依赖模块需要编译打包处理,使用Babel将ES6编译为ES5代码
export:导出模块,引入模块:import
1. 定义package.json
2. 安装依赖包
安装babel-cli, babel-preset-es2015和browserify
npm install babel-cli browserify -g
npm install babel-preset-es2015 --save-dev
presets 预设(将es6转换成es5的所有插件打包)
3. 定义.babelrc文件
{
"presets": ["es2015"]
}
4. 编码
module1.js 分别暴露
define(function (require, exports, module) {
//内部变量数据
var data = 'atguigu.com'
//内部函数
function show() {
console.log('module1 show() ' + data)
}
//向外暴露
exports.show = show
})
module2.js 统一暴露
let data = 'module2 data'
function fun1() {
console.log('module2 fun1() ' + data);
}
function fun2() {
console.log('module2 fun2() ' + data);
}
export {fun1, fun2}
module3.js export default
export default {
name: 'Tom',
setName: function (name) {
this.name = name
}
}
app.js 引入模块 import
import {foo, bar} from './module1'
import {DATA_ARR} from './module1'
import {fun1, fun2} from './module2'
import person from './module3'
import $ from 'jquery'
$('body').css('background', 'red')
foo()
bar()
console.log(DATA_ARR);
fun1()
fun2()
person.setName('JACK')
console.log(person.name);
5. 编译
* 使用Babel将ES6编译为ES5代码(但包含CommonJS语法) : babel js/src -d js/lib
* 使用Browserify编译js : browserify js/lib/app.js -o js/lib/bundle.js
6. 页面中测试引入
<script type="text/javascript" src="js/lib/bundle.js"></script>
7. 引入第三方模块(jQuery)
1). 下载jQuery模块:
npm install jquery@1 --save
2). 在app.js中引入并使用
import $ from 'jquery'
$('body').css('background', 'red')
标签:function,exports,console,log,模块化,js,模块 From: https://blog.csdn.net/weixin_42289279/article/details/136028783