模塊化 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會使性能變慢.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章