模塊化開發
模塊化只是一種思想
模塊化演變過程
- Stage 1 - 文件劃分方式
- 將功能與數據放置到不同的文件當中
- 約定每個文件都是一個獨立的模塊
- 缺點:
- 每個模塊都在全局作用域下工作,污染全局作用域,容易出現命名沖突
- 無法管理模塊之間的依賴關系
- 模塊內的成員可以被其他模塊隨意修改
- 完全依靠約定,當項目變得龐大以后,難以維護
- Stage 2 - 命名空間方式
- 每個模塊只暴露一個全局對象
- 所有成員與方法都掛載在這個全局對象下
- 解決了全局作用域污染與命名沖突的問題
- 缺點:
- 依然無法管理模塊之間的依賴關系
- 模塊的內的成員依然可以被修改
- Stage 3 - IIFE(立即執行函數)方式
- 使用立即執行函數,為模塊創建私有空間
- 對于需要對外暴露的內容,可以掛載到window對象上
- 解決了模塊內成員可以被隨意修改的問題
- Stage 4 - 模塊化規范出現
- CommonJS規范 - NodeJS模塊化規范
- 一個文件就是一個模塊
- 每個模塊有單獨的作用域
- 通過module.exports導出成員
- 通過require函數加載模塊
- 同步模式加載模塊(在瀏覽器環境效率不高)
- AMD(Asynchronous Module Definition)- 異步模塊定義規范
- require.js實現了AMD規范,同時是一個功能強大的模塊加載器
- 約定使用define函數定義一個模塊,接收三個參數
- 第一個參數:模塊名稱
- 第二個參數:聲明依賴數組
- 第三個參數:提供私有空間的函數,通過return向外部導出成員
- 使用require函數加載模塊
- 絕大多數第三方庫都支持AMD規范
- AMD模塊使用起來相對復雜
- 模塊JS請求相對頻繁
- CMD(Common Module Definition)- 通用模塊定義規范
- 由淘寶前端團隊推出的sea.js定義并實現了CMD規范
- 類似CommonJS規范
- 通過require加載依賴
- 通過module.exports或exports對外暴露成員
- 被require.js兼容
- CommonJS規范 - NodeJS模塊化規范
模塊化標準規范
ES Module - ES2015中定義,并在語言層面實現的模塊化規范
模塊化的最佳實踐,NodeJS環境下使用CommonJS規范,瀏覽器環境下使用ES Module
ES Module特性
- 自動采用嚴格模式
- 運行在獨立私有作用域中
- 通過CORS方式請求外部JS模塊
- 即script被標識為type=module方式引入外部資源時,會受到瀏覽器同源策略限制
- script加載外部JS時,會延遲執行腳本,等同于使用defer屬性,不影響頁面渲染,執行順序不按引用順序
ES Module的導入導出
-
通過export導出
-
常見用法
export const a = 1 export const fn = () => {} export default 123 export { a, fn as b } export t from './module.js'
-
注意事項
-
export { obj }
與export default { obj }
-
export { obj }
export后面跟的不是字面量對象,而是固定的語法 -
export default { obj }
export default后面跟的是一個值,這里{ obj }
表示字面量對象
-
- export導出的是成員的引用,而不是成員值的拷貝,這與CommonJS不同
-
-
-
通過import導入
-
常見用法
import { a, b, default as n } from './es-module.js'
-
注意事項
-
import { obj } from xxx
import后面的括號不是解構寫法,而是固定的語法 - import導入的對象是只讀的,不允許修改
- import導入文件路徑不可省略(相對路徑或者絕對路徑)
- 不支持表達式方式,如果需要動態加載模塊,可以使用import()函數,該函數返回一個Promise對象
-
-
ES Module瀏覽器環境polyfill
browser-es-module-loader
- 工作原理:
- 讀取ES Module腳本
- 交給babel進行轉換
- 執行轉換后的代碼
- 注意事項
- 在支持ES Module的瀏覽器環境下,會導致重復執行
- 可以使用script的nomodule屬性,只會在不支持ES Module的瀏覽器環境下加載腳本
ES Module in Node.js
Node.js中目前可以使用ES Module語法加載或者導出模塊,屬于實驗特性
-
要在node環境下使用ES Module
JS文件需要使用.mjs結尾(新版本node在package.json中標識type: module時,可以直接使用.js文件后綴,此時想使用CommonJS模塊,需使用.cjs結尾)
-
執行時,需要添加
--experimental-modules
參數開啟實驗特性// 注意,必須先跟--experimental-modules參數,再接文件名 node --experimental-modules import.mjs
-
使用import加載其他模塊
- 第三方模塊:無法使用提取成員的方式
- 系統內置模塊:官方做了兼容性處理,可以正常提取成員
- CommonJS模塊:導出一個對象,因此無法使用提取成員的方式加載模塊,可以使用加載default默認對象的方式
CommonJS模塊無法直接加載ES Module
-
ES Module與CommonJS模塊的差異
- ES Module下無法訪問CommonJS內置成員及方法
require、module、exports、__filename、__dirname
- ES Module下無法訪問CommonJS內置成員及方法