模块化
-
什么是模块化?
- 将一个复杂的程序依据一定的规则(规范)封装成几个块(文件),并进行组合在一起
- 块的内部数据/实现是私有的,只是向外暴露一些接口(方法)与外部其它模块通信
- 编码时是按照模块一个一个编码的,整个项目就是一个模块化的项目
-
一个模块的组成
- 数据——>内部的属性
- 操作数据的行为——>内部的函数
-
模块化的发展
-
全局function模式
- 编码:全局变量/函数
- 问题:污染全局命名空间,容易引起命名冲突/数据不安全
-
namespace模式
- 编码:将数据/行为封装在对象中
- 解决:命名冲突(减少了全局变量)
- 问题:数据不安全(外部可以直接修改模块内部的数据)
-
IIFE模式/增强
-
IIFE:立即调用函数——>匿名函数自调用
-
编码:将数据和行为封装在一个函数内部,通过window添加属性来向外暴露接口
-
引入依赖:通过函数形参来引入依赖模块
(function(window, module1){ var data = '123' function foo() { module1.xxx() console.log('foo()'+data) } function bar() { console.log('bar()'+data) } window.module = {foo} })(window, module1)
-
-
-
模块化规范
-
CommonJS
-
Node.js:服务器端
-
Browserify:浏览器端,也称为js的打包工具
-
基本语法:
-
定义暴露模块:exports
exports.xxx = value module.exports = value
引入模块:require
var module = require('模块名/模块相对路径')
-
引入模块发生在什么时候?
- Node:运行时,动态同步引入
- Browserify:在运行前对模块进行编译/转义/打包的处理(已经将依赖的模块包含进来了),运行的是打包生成的js,运行时不存在需要再从远程引入依赖模块
-
-
-
AMD:浏览器端
- require.js
-
基本语法
-
定义暴露模块:
define([依赖模块名], function(){return 模块对象})
-
引入模块:
require(['模块1', '模块2', '模块3'], function(m1, m2){//使用模块对象})
-
配置:
require.config({ //基本路径 baseUrl : 'js/', //标识名称与路径的映射 paths : { '模块1' : 'modules/模块1', '模块2' : 'modules/模块2', 'angular' : 'libs/angular', 'angular-messages' : 'libs/angular-messages' }, //非AMD的模块 shim : { 'angular' : { exports : 'angular' }, 'angular-messages' : { exports : 'angular-messages', deps : ['angular'] } } })
-
-
CMD : 浏览器端
-
sea.js
-
基本语法
-
定义暴露模块:
define(function(require, module, exports){ 通过require引入依赖模块 通过module/exports来暴露模块 exports.xxx = value })
-
使用模块seajs.use([‘模块1’, ‘模块2’])
-
-
-
ES6
-
ES6内置了模块化的实现
-
基本语法
-
定义暴露模块:export
-
暴露一个对象:
export default 对象
-
暴露多个:
// 方法一: export var xxx = value1 export let yyy = value2 // 方法二: var xxx = value1 let yyy = value2 export {xxx, yyy}
-
-
引入使用模块:import
-
default模块:
import xxx from '模块路径/模块名'
-
其它模块
import {xxx, yyy} from '模块路径/模块名' import * as module1 from '模块路径/模块名'
-
-
-
问题:所有浏览器还不能直接识别ES6模块化的语法
-
解决:
- 使用Babel将ES6转成ES5(使用了CommonJS)——此时浏览器还是不能直接执行
- 使用Browserify进行打包处理——此时浏览器可以运行
-
-
Node.js模块化教程
-
下载安装node.js
-
创建项目结构
|-modules |-module1.js |-module2.js |-module3.js |-app.js |-package.json { "name": "commonJS-node", "version": "1.0.0" }
-
下载第三方模块
如果用到第三方模块,用npm下载
npm i uniq --save
-
模块化编码
-
module1.js
module.exports = { foo() { console.log('moudle1 foo()') } }
-
module2.js
module.exports = function () { console.log('module2()') }
-
module3.js
exports.foo = function () { console.log('module3 foo()') } exports.bar = function () { console.log('module3 bar()') }
-
app.js
/** 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]))
-
-
通过node运行app.js
node app.js
Browserify模块化教程
-
创建目录结构
|-js |-dist //打包生成文件的目录 |-src //源码所在的目录 |-module1.js |-module2.js |-module3.js |-app.js //应用主源文件 |-index.html |-package.json { "name": "browserify-test", "version": "1.0.0" }
-
下载browserify
- 全局:
npm i browserify -g
- 局部:
npm i browserify --save-dev
- 全局:
-
定义模块代码
同Node.js模块化编码
-
打包处理js
browserify js/src/app.js -o js/dist/bundle.js
-
页面使用引入
<script type="text/javascript" src="js/dist/bundle.js"></script>
AMD-RequireJS模块化教程
-
下载require.js,并引入
- 官网: http://www.requirejs.cn/
- github : https://github.com/requirejs/requirejs
- 将require.js导入项目: js/libs/require.js
-
创建目录结构
|-js |-libs |-require.js |-modules |-alerter.js |-dataService.js |-main.js |-index.html
-
定义require.js的模块化代码
-
module1.js
define({ msg : "这个模块他没有依赖其他模块", getMsg() { console.log(`module1 ${this.msg}`) } })
-
module2.js
define(function () { let msg = "这个模块他没有依赖其他模块" function getMsg() { console.log(`module2 ${msg}且使用了一个函数做一些工作`) } return { getMsg } })
-
module3.js
define(["module1", "module2", "jquery"], function (m1, m2, $) { let msg = '这个模块依赖了其他模块' function showMsg() { $('body').css('background', 'red') m1.getMsg() m2.getMsg() } return { showMsg } })
-
-
应用入口js:main.js
(function () { // 配置 requirejs.config({ // 基本路径 baseUrl: 'js/', // 模块标识名和模块路径映射 paths: { // 自定义模块 module1: 'modules/module1', module2: 'modules/module2', module3: 'modules/module3', // 第三方库模块 jquery: 'libs/jquery' } }) // 引入使用模块 requirejs(['module3'], function (m3) { m3.showMsg() }) })()
-
在页面使用模块
<script data-main="js/main" src="js/libs/require.js"></script>
-
使用第三方基于require.js的框架(jquery)
-
将jquery的库文件导入到项目: js/libs/jquery-1.10.1.js
-
在main.js中配置jquery路径
paths: { 'jquery': 'libs/jquery-1.10.1' }
-
在module3.js中使用jquery
define(['dataService', 'jquery'], function (dataService, $) { var name = 'xfzhang' function showMsg() { $('body').css({background : 'red'}) alert(name + ' '+dataService.getMsg()) } return {showMsg} })
-
-
使用第三方不基于require.js的框架(angular)
-
将angular.js导入项目
-
js/libs/angular.js
-
在main.js中配置
(function () { require.config({ //基本路径 baseUrl: "js/", //模块标识名与模块路径映射 paths: { //第三方库 'jquery' : './libs/jquery-1.10.1', 'angular' : './libs/angular', //自定义模块 "alerter": "./modules/alerter", "dataService": "./modules/dataService" }, /* 配置不兼容AMD的模块 exports : 指定与相对应的模块名对应的模块对象 */ shim: { 'angular' : { exports : 'angular' } } }) //引入使用模块 require( ['alerter', 'angular'], function(alerter, angular) { alerter.showMsg() console.log(angular); }) })()
-
CMD-SeaJS模块化教程
-
下载sea.js,并引入
- 官网: http://seajs.org/
- github : https://github.com/seajs/seajs
- 将sea.js导入项目: js/libs/sea.js
-
创建项目结构
|-js |-libs |-sea.js |-modules |-module1.js |-module2.js |-module3.js |-module4.js |-main.js |-index.html
-
定义sea.js的模块代码
-
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) { 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模块化教程
ES6-Babel-Browserify
-
创建项目结构
|-js |-src |-app.js |-module1.js |-module2.js |-module3.js |-index.html |-babel.config.json |-package.json
-
安装babel相关包和browserify
babel官网:https://www.babeljs.cn/docs/usage
npm i --save-dev @babel/core @babel/cli @babel/preset-env
npm i browserify -g
+npm
i browserify --save-dev
-
在根目录下定义babel.config.json文件
{ "presets": ["@babel/preset-env"] }
-
编码
-
module1.js分别暴露
export function foo() { console.log(`module1 foo()`) } export function bar() { console.log(`module1 bar()`) } export const DATA_ARR = [1, 2, 3, 4, 5]
-
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 { name: 'default', setName(name) { this.name = name } }
-
app.js
import { foo, bar, DATA_ARR } from './module1' import { fun1, fun2 } from './module2' import person from './module3' import $ from 'jquery' $('body').css('background', 'pink') foo() bar() console.log(DATA_ARR) fun1() fun2() person.setName('默认') console.log(person.name)
-
-
编译
- 使用Babel将ES6编译为ES5代码(但包含CommonJS语法):
- 方法一:
./node_modules/.bin/babel js/src --out-dir js/lib
- 方法二:
npx babel js/src --out-dir js/lib
- 方法一:
- 使用Browserify编译js:
browserify js/lib/app.js -o js/lib/bundle.js
- 使用Babel将ES6编译为ES5代码(但包含CommonJS语法):
-
页面中引入测试
<script type="text/javascript" src="js/lib/bundle.js"></script>
-
引入第三方模块(jQuery)
-
下载jQuery模块:
npm i jquery@1 --save
-
在app.js中引入并使用
import $ from 'jquery' $('body').css('background', orange)
-