6-前端模組化
一、為什麼需要模組化
1、JavaScript的原始功能
在網頁開發的早期,js 製作作為一種指令碼語言,做一些簡單的表單驗證或動畫實現等,那個時候程式碼很少,直接將程式碼寫在 <script> 標籤中即可:
<script> document.getElementById('button').onclick = function(){ console.log('按鈕發生了點選'); } </script>
隨著 ajax 非同步請求的出現,慢慢形成了前後端的分離,客戶端需要完成的事情越來越多,程式碼量也是與日俱增,為了應對程式碼量的劇增,
我們通常會將程式碼組織在多個js檔案中,進行維護,但是這種維護方式,依然不能避免一些災難性的問題;
比如全域性變數同名問題:
// a.js 檔案中,小明定義了一個變數 flag , 值為 true
flag = true
// b.js 檔案中,小紅也定義了一個變數 flag , 值為 false
flag = false
// main.js 檔案中,小明想通過 flag 進行一些判斷,完成後續的事情
if (flag) {
console.log('小明是個畫家'); // 結果可能會因為flag同名的問題,而出現邏輯錯誤
}
另外,這種程式碼的編寫方式對 js 檔案的依賴順序幾乎是強制性的,當 js 檔案過多,比如有幾十個的時候,弄清楚它們的順序是一件比較麻煩的事情,
而且即使你弄清楚順序了,也不能避免上面出現的這種尷尬問題的發生;
這時,我們可以使用匿名函式來解決方面的重名問題;
2、匿名函式的解決方案
在 a.js 檔案中,我們使用匿名函式:
(function(){
flag = true
})()
使用匿名函式雖然解決了重名問題,但是如果我們希望在 main.js 檔案中,用到 flag,應該如何處理呢?
顯然,另外一個檔案中不方便使用,因為 flag 是一個區域性變數。
這時,我們可以將需要暴露到外面的變數,使用一個模組作為出口。
3、使用模組作為出口
// 使用模組作為出口 var ModuleA = (function(){ // 1. 定義一個物件 var obj = {} // 2. 在物件內部新增變數和方法 obj.flag = true obj.myFunc = function(info){ console.log(info); } // 3. 將物件返回 return obj })()
以上程式碼在匿名函式內部,定義一個物件,給物件新增各種需要暴露到外面的屬性和方法(不需要暴露的直接定義即可),
最後將這個物件返回,並且在外面使用了一個 MoudleA 接受。
接下來,在 main.js 中使用只需要使用屬於自己模組的屬性和方法即可:
// 使用模組
if(ModuleA.flag){
console.log('小明是個畫家');
}
ModuleA.myFunc('小明是個畫家')
console.log(ModuleA);
這就是模組最基礎的封裝,事實上模組的封裝還有很多高階的話題,幸運的是,前端模組化開發已經有了很多既有的規範,以及對應的實現方案;
常見的模組化規範:
- CommonJS
- AMD
- CMD
- ES6 Modules
4、瞭解CommonJS
模組化有兩個核心: 匯入、匯出
// CommonJS 匯出
// 在a.js中:
module.exports = {
flag: true,
sum(a, b) {
return a + b
}
}
// CommonJS 匯入
// 在main.js中:
let {flag,sum} = require('a.js')
5、ES6的export和import
(1)export基本使用
export指令用於匯出變數,比如下面的程式碼:
// info.js
export let name = 'lyy'
export let age = '18'
export let height = '1.75'
上面的程式碼還有另外一種寫法:
// info.js
let name = 'lyy'
let age = '18'
let height = '1.75'
export {name, age, height}
(2)匯出函式或類
上面我們主要是輸出變數,也可以輸出函式或者輸出類
上面的程式碼也可以寫成這種形式:
(3)export default
某些情況下,一個模組中包含某個的功能,我們並不希望給這個功能命名,而且讓匯入者可以自己來命名
這個時候就可以使用 export default
// info.js
export default function(){
conse.log('default function')
}
來到 main.js 中,這樣使用就可以了:
import myFunc from './info.js'
myFunc()
這裡的 myFunc 是自己命名的,可以根據需要命名它對應的名字
另外,需要注意:
export default 在同一個模組中,不允許同時存在多個
(4)import使用
我們使用 export 指令匯出了模組對外提供的介面,就可以通過 import 命令來載入對應的這個模組了
首先,需要在HTML程式碼中引入兩個 js 檔案,並且型別需要設定為 module:
<script src="info.js" type="module"></script> <script src="main.js" type="module"></script>
import指令用於匯入模組中的內容,比如main.js的程式碼:
import {name,age,height} from "./info.js"
如果我們希望某個模組中所有的資訊都匯入,一個個匯入顯然有些麻煩,則可以匯入模組中所有的 export 變數,
但是通常情況下我們需要給起一個別名,方便後續的使用:
import * as info from "./info.js"
console.log(info.name,info.age,info.height)