模块化 CDM AMD

为什么会有模块

我们最初只会有index.js的文件,后来随着业务的发展,这个代码发展到了1000多行,就很难读懂并且很难维护了了,因此我们就想到了分块,就是把相同业务逻辑的代码放在一起,这个就是模块.通常是会把一个文件看作一个模块的,每个模块文件都有其特定的功能,便于复用。通过使用模块,使我们能够在开发环境上更好地开发和维护我们的项目。我在写游戏项目的时候我把app.js写成element,js,enemy.js等,这个就是模块化思想.

我们把1000多行代码按功能分了不同的代码块,就是分别引用在了index.html里,例如如下:

<script src="common.js"></script>
<script src="a.js"></script>
<script src="b.js"></script>
<script src="c.js"></script>

这样实现模块化存在两大问题

  • 命名冲突(不同的文件里可能会出现相同的变量,不能实现私有化)
  • 管理模块依赖艰难(得分析模块之间的依赖,文件数多,就会很麻烦)
    因此模块化规范诞生了,规范化的模块会使我们统一方法定义模块,不需要手动维护依赖。

模块化规范

目前我们有3类模块化规范

  • CommonJs
  • AMD异步模块定义
  • CMD通用模块定义

CommonJS规范

  • 文件即模块,一个文件即模块,每个文件拥有自己的作用域
  • 使用 module.exports属性(或简写exports)来暴露对外的接口和属性
  • 使用 require(moduleName) 来同步加载依赖模块

以下为一个例子:

math.js
/**
*创建计算圆形面积函数
*@param {Number} r 圆形面积
*@return {Number} 圆形面积
**/

functiuon area(r){
   return Math.pi*r*r;
}
// 暴露对外接口
module.exports={
	area:area
}
circle.js
/**
 * 模块circle
 */

var math=require('./math')
var radius=10;
// 计算圆形面积 
math.area(radius);

AMD & RequireJs

CommonJs是同步加载模块,适用在node服务端(文件存在本地硬盘),而不适合于浏览器端(通过网络加载,同步加载会阻塞页面).因此我们需要异步加载模块,AMD(Asynchronous Module Defenition)就诞生了.

  • 使用 define(id?, dependencies?, factory) 函数来定义模块
  • 使用 require(modules, callback) 函数来加载模块

在这里插入图片描述

id 是模块的标识,如果不写,如果不写默认就是我们加载的脚本文件的名字。
在这里插入图片描述
第二个参数是依赖的模块数组,默认是[‘require’,‘exports’,‘module’].
在这里插入图片描述
使用方法如下:

// 没有依赖其他模块的定义方式
difine('moduleA',function(require,exports,module){
	exports.getNum=function(){
		return 5;
	}
});

// 依赖其他模块
define('moduleD',['moduleA'],function(moduleA){
	// 通过模块A的方法初始化变量index
	let index=moduleA.getNum();
	// 通过return来暴露addIndex方法
	return {
		addIndex:function(){
			index+1;
		}
	}
})

另一个方法是require(modules,callback) 第一个参数是加载的模块,第二个参数是要执行的函数.

require(['moduleA,moduleB'],function(moduleA,moduleB){
	// 加载完模块A和模块B后的回调函数
	
})

Javascript没有原声的支持AMD规范,因此需要一个模块加载器,就是requireJS.requireJS会在运行时递归的分析依赖,查找模块路径,动态插入script,监听加载事件。

ES6的模块化

简单来说,ES6 模块的设计思想就是:一个 JS 文件就代表一个 JS 模块。在模块中你可以使用 import 和 export 关键字来导入或导出模块中的东西。
ES6 模块主要具备以下几个基本特点:

  • 自动开启严格模式,即使你没有写 use strict
  • 每个模块都有自己的上下文,每一个模块内声明的变量都是局部变量,不会污染全局作用域
  • 模块中可以导入和导出各种类型的变量,如函数,对象,字符串,数字,布尔值,类等
  • 每一个模块只加载一次,每一个 JS 只执行一次, 如果下次再去加载同目录下同文件,直接从内存中读取。 一个模块就是一个单例,或者说就是一个对象

export

// 个人所得税计算模块
// 在线参考站点:[个人所得税](http://www.gerensuodeshui.cn/)
// personal-income-tax.js

// 个税起征点
export const taxBasicNum = 3500;

// 税率等级
export const taxRatioLevel = [
    {
        num: 1500, // 小于1500
        ratio: '3%',
        subtract: 0, // 速算扣除数
    }, 
    {
        num: 4500, // 大于1500,小于4500
        ratio: '10%',
        subtract: 105,
    }, 
    {
        num: 9000, // 大于4500,小于9000
        ratio: '20%',
        subtract: 555,
    }, 
    {
        num: 35000, // 大于9000,小于35000
        ratio: '25%',
        subtract: 1005,
    }, 
    {
        num: 55000,  // 大于35000,小于55000
        ratio: '30%',
        subtract: 2755,
    }, 
    {
        num: 80000,  // 大于55000,小于80000
        ratio: '35%',
        subtract: 5505,
    }, 
    {
        num: 80000,  // 大于80000
        ratio: '45%',
        subtract: 13505,
    }];

// 所缴税收
// 应纳税所得额 = 应发工资 - 五险一金 - 个税起征点
// 所缴税收 = 应纳税所得额 * 税率 - 速算扣除数
export function calTax (num, insurance) {
    let taxShouldNum = num - insurance - taxBasicNum;
    let tax;
    switch (true) {
        case taxShouldNum < taxRatioLevel[0].num:
            tax = taxShouldNum * taxRatioLevel[0].ratio - taxRatioLevel[0].subtract;
            break;
        case taxShouldNum < taxRatioLevel[1].num:
            tax = taxShouldNum * taxRatioLevel[1].ratio - taxRatioLevel[1].subtract;
            break;
        case taxShouldNum < taxRatioLevel[2].num:
            tax = taxShouldNum * taxRatioLevel[2].ratio - taxRatioLevel[2].subtract;
            break;
        case taxShouldNum < taxRatioLevel[3].num:
            tax = taxShouldNum * taxRatioLevel[3].ratio - taxRatioLevel[3].subtract;
            break;
        case taxShouldNum < taxRatioLevel[4].num:
            tax = taxShouldNum * taxRatioLevel[4].ratio - taxRatioLevel[4].subtract;
            break;
        case taxShouldNum < taxRatioLevel[5].num:
            tax = taxShouldNum * taxRatioLevel[5].ratio - taxRatioLevel[5].subtract;
            break;
        case taxShouldNum > taxRatioLevel[6].num:
            tax = taxShouldNum * taxRatioLevel[6].ratio - taxRatioLevel[6].subtract;
            break;
        default:
            tax = 0;
    }

    return tax;
}

// 实发工资
export function calWages(num, insurance) {
    let tax = calTax(num, insurance);
    let wages = num - insurance - tax;

    return wages;
}

import

// main.js
import {taxBasicNum, taxRatioLevel, calTax, calWages} from './personal-income-tax';

// 可以使用 taxBasicNum 输出一段话,说明个税的起征点是多少
console.log(`个税起征点为:taxBasicNum`);
// 还可以使用 taxRatioLevel 数据输出一个表格,对应各个等级的税率,这里就不演示了

// 计算20000元缴纳了五险一金3000后,应该缴纳多少税收及实际税后工资为多少
let tax = calTax(20000, 3000);
let wages = calWages(20000, 3000);

更详细的介绍:
在这里插入图片描述

index.js
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>Document</title>
	</head>
	<body>
		<!-- module  -->
		<script type="module" src="main.js"></script>
	</body>
</html>
module.js
// 导出方法1
export var a = 1;
export var b = 2;

// 导出方法2
var c=3;
var d=4;
export { c,d };
export { c as myC,d as myD }

// 导出方法3
export default []
import arr,{ a,b,c,d,myC,myD } from './module.js';
console.log(a);
console.log(b);


// 第二种方式
console.log(c);
console.log(d);

// 第二种导入方式的另一种用法
console.log(myC);
console.log(myD);

// 第3种导入方法
console.log(arr);

// 第4种整体倒入  正常导入 
import * as m from './module.js';
console.log(m);


// 异步导入
import ('./module.js').then(function(m){
	console.log(m);
});

我个人觉得应该尽量使用ES6的export,import 而不是AMD 和CMD,因为requireJs会使性能变慢.

发布了83 篇原创文章 · 获赞 18 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/Abudula__/article/details/102651924
今日推荐