模块化

模块化进化史

1.全局 functon 模式

//module1.js
//数据
let data = 'atguigu.com'

//操作数据的函数
function foo() {
	console.log(`foo() ${data}`)
}
<script type="text/javascript" src="module1.js"></script>
<script type="text/javascript">
	//全局函数模式: 将不同的功能封装成不同的全局函数
	//问题: Global 被污染了, 很容易引起命名冲突
	let data = "修改后的数据"
	foo()
</script>

2.namespace 模式

// module2.js
let myModule = {
	data: 'atguigu.com',
	foo() {
		console.log(`foo() ${this.data}`)
	}
}
<script type="text/javascript" src="module2.js"></script>
<script type="text/javascript">
	//namespace模式: 简单对象封装
	//作用: 减少了全局变量
	//问题: 不安全
	myModule.foo()

	myModule.data = 'other data' //能直接修改模块内部的数据
	myModule.foo()

</script>

3.IIFE 模式

//module3.js
(function (window) {
	//数据
	let data = 'atguigu.com'

	//操作数据的函数
	function foo() { //用于暴露函数
		console.log(`foo() ${data}`)
	}

	//暴露行为
	window.myModule = {foo}
})(window)
<script type="text/javascript" src="module3.js"></script>
<script type="text/javascript">
	//IIFE模式: 匿名函数自调用(闭包)
	//IIFE : immediately-invoked function expression(立即调用函数表达式)
	//作用: 数据是私有的, 外部只能通过暴露的方法操作
	//问题: 如果当前这个模块依赖另一个模块怎么办?
	myModule.foo()
	console.log(myModule.data) //undefined 不能访问模块内部数据
	myModule.data = 'xxxx' //不是修改的模块内部的 data
	myModule.foo() //没有改变
</script>

4.IIFE模式增强

//引入 jquery 到项目中
//module4.js
(function (window, $) {
	//数据
	let data = 'atguigu.com'

	//操作数据的函数
	function foo() { //用于暴露有函数
		console.log(`foo() ${data}`)
		$('body').css('background', 'red')
	}

	//暴露行为
	window.myModule = {foo}
})(window, jQuery)
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="module4.js"></script>
<script type="text/javascript">
	//IIFE 模式增强: 引入依赖
	//这就是现代模块实现的基石
	myModule.foo()
	//一个页面需要引入多个js文件
	//问题:
		//请求过多
		//依赖模糊
		//难以维护
	//这些问题可以通过现代模块化编码和项目构建来解决
</script>

commonjs

服务器 nodejs
客户端 browserify 也称为 commonjs 的浏览器端的打包工具

1.下载安装node.js

2.创建项目结构

|-modules
	|-module1.js
	|-module2.js
	|-module3.js
|-app.js
|-package.json //npm init
	{
		"name": "commonJS-node",
		"version": "1.0.0"
	}

3.下载第三方模块 npm install uniq --save

4.模块化编码

//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]))

fs.readFile('app.js', function (error, data) {
	console.log(data.toString())
})

5.通过 node 运行 app.js node app.js

ES6 (Babel-Browserify)

1. 定义 package.json 文件

{
	"name" : "es6-babel-browserify",
	"version" : "1.0.0"
}

2.安装 babel-cli, babel-preset-es2015 和 browserify

- npm install babel-cli browserify -g  
- npm install babel-preset-es2015 --save-dev 

3.定义 .babelrc 文件

{
	"presets": ["es2015"]
}

4.编码

// js/src/module1.js
export function foo() {
	console.log('module1 foo()');
}
export let bar = function () {
	console.log('module1 bar()');
}
export const DATA_ARR = [1, 3, 5, 1]
// js/src/module2.js
let data = 'module2 data'

function fun1() {
	console.log('module2 fun1() ' + data);
}

function fun2() {
	console.log('module2 fun2() ' + data);
}

export { fun1, fun2 }
// js/src/module3.js
export default {
	name: 'Tom',
	setName: function (name) {
		this.name = name
	}
}
// js/src/app.js
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)

  • 下载 jQuery 模块: npm install jquery@1 --save
  • 在 app.js 中引入并使用
    js import $ from 'jquery' $('body').css('background', 'red')

AMD-RequireJS 模块化 (专用于浏览器端)

1.下载require.js, 并引入

2.创建项目结构

|-js
	|-libs
		|-require.js
	|-modules
		|-alerter.js
		|-dataService.js
	|-main.js
|-index.html

3.定义 require.js 的模块代码

//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}
})

4.应用主(入口)js: main.js

(function () {
	//配置
	require.config({
		//基本路径
		baseUrl: "js/",
		//模块标识名与模块路径映射
		paths: {
			"alerter": "modules/alerter",
			"dataService": "modules/dataService",
		}
	})
	//引入使用模块
	require( ['alerter'], function(alerter) {
		alerter.showMsg()
	})
})()

5.页面使用模块:

<script data-main="js/main" src="js/libs/require.js"></script>

6.使用第三方基于 require.js 的框架(jquery)

  • 将 jquery 的库文件导入到项目: js/libs/jquery-1.10.1.js

  • 在 main.js 中配置 jquery 路径

    paths: {
    	'jquery': 'libs/jquery-1.10.1'
    }
    
  • 在 alerter.js 中使用 jquery

    define(['dataService', 'jquery'], function (dataService, $) {
    		var name = 'xfzhang'
    		function showMsg() {
    				$('body').css({background : 'red'})
    				alert(name + ' '+dataService.getMsg())
    		}
    		return {showMsg}
    })
    

7.使用第三方不基于 require.js 的框架(angular/angular-messages)

  1. 将 angular.js 和 angular-messages.js 导入项目
    • js/libs/angular.js
    • js/libs/angular-messages.js
  2. 在 main.js 中配置
    (function () {
    	require.config({
    		//基本路径
    		baseUrl: "js/",
    		//模块标识名与模块路径映射
    		paths: {
    			//第三方库
    			'jquery' : 'libs/jquery-1.10.1',
    			'angular' : 'libs/angular',
    			'angular-messages' : 'libs/angular-messages',
    			//自定义模块
    			"alerter": "modules/alerter",
    			"dataService": "modules/dataService"
    		},
    		/*
    		配置不兼容AMD的模块
    		exports : 指定导出的模块名
    		deps  : 指定所有依赖的模块的数组
    		*/
    		shim: {
    			'angular' : {
    				exports : 'angular'
    			},
    			'angular-messages' : {
    				exports : 'angular-messages',
    				deps : ['angular']
    			}
    		}
    	})
    	//引入使用模块
    	require( ['alerter', 'angular', 'angular-messages'], function(alerter, angular) {
    		alerter.showMsg()
    		angular.module('myApp', ['ngMessages'])
    		angular.bootstrap(document,["myApp"])
    	})
    })()
    
  3. 页面:
    <form name="myForm">
    	用户名: <input type="text" name="username" ng-model="username" ng-required="true">
    	<div style="color: red;" ng-show="myForm.username.$dirty&&myForm.username.$invalid">用户名是必须的</div>
    </form>
    

CMD-SeaJS 模块化 (专用于浏览器端)

1.下载 sea.js, 并引入

2.创建项目结构

|-js
	|-libs
		|-sea.js
	|-modules
		|-module1.js
		|-module2.js
		|-module3.js
		|-module4.js
		|-main.js
|-index.html

3.定义 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()
})

4.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>

UMD(AMD和Commonjs的糅合)

UMD 先判断是否支持 Node.js 的模块(exports)是否存在,存在则使用 Node.js 模块模式。再判断是否支持 AMD(define 是否存在),存在则使用 AMD 方式加载模块。

(function (window, factory) {
  if (typeof exports === 'object') {  
    module.exports = factory();
  } else if (typeof define === 'function' && define.amd) {
    define(factory);
  } else {
    window.eventUtil = factory();
  }
})(this, function () {
  //module ...
});
posted @   提莫一米五呀  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示