最近在搞跨平臺解決方案,討論關於模塊劃分的問題以及如何儘可能多的複用邏輯代碼。因而就有了此文章,以前的博客也寫過,不過因爲主機商跑路,寶貴的資源也就沒了,說多了都是淚~ 這裏按模塊化發展的歷史回溯的時間序html
這個是目前前端小夥伴接觸的最多的,是瀏覽器和服務端通用的模塊化解決方案,主要命令爲:export
和import。export
用於導出本模塊對外的接口,import
用於導入某個模塊的功能。前端
//modulA.js export var goingta = "goingta"; export function hello() { console.log("hello world"); } const fn = function() { goingta = "new goingta"; console.log("fn"); }; export { fn }; const come = 1; export default come; // export default const errorDefault = 2 // default 不能導出變量表達式 //index.js import come, { fn, hello } from "./moduleA.js"; import * as aModule from "./moduleA.js"; fn(); hello(); console.log("come", come); console.log("aModule", aModule); //aModule Module{default: 1, fn: ƒ (),…} console.log("aModule.goingta", aModule.goingta); //new goingta
從上面例子,咱們能夠看到export
能夠在任意地方導出變量,方法,而且也能夠將已有變量或方法包在一個{}
對象裏面導出,可是最終都會包在一個{}
裏面,簡單理解就是:jquery
1. 若是單獨導出一個變量或方法則是往將要導出{}對象裏面添加屬性。
2. 若是導出的是{},則和已生成的導出{}對象合併。es6
而後說一下特例export default
,這個是在導出對象裏面加一個default
屬性,還有一點值得注意的是export default
後面不能跟變量表達式。後端
最後還有一個重點是,ES6 Moudle是編譯時輸出,而且是值引用。瀏覽器
CommonJS
最主要的表明就是Node.js
,主要命令:module
、exports
、require
。其中有個使人疑惑的點是exports
和module.exports
,其實理解起來也很簡單,就是在模塊裏面加了一句: exports = module.exports = {};
exports
和module.exports
指向同一個內存區域,只要在exports
加了屬性,則module.exports
會跟着變化,可是最終導出對外的接口是以module.exports
爲準,因此不推薦直接使用exports
。例如:性能優化
//moduleA.js let goingta = "我是goingta"; exports.goingta = goingta; exports.fn = function() { goingta = "new goingta"; }; exports = "把exports指向其餘區域"; module.exports = "我如今沒有goingta了,也沒有fn了"; // 這行代碼註釋掉會有不同的結果 // index.js let obj = require("./moduleA.js"); console.log(obj);
最終輸出的是:"我如今沒有goingta了,也沒有fn了",若是把最後一行代碼註釋掉則輸出:{goingta: "我是goingta", fn:ƒ ()}異步
對於CommonJS
規範來講,很重要的一點是CommonJS
輸出的是一個值拷貝,而且是運行時加載。async
把上面的示例代碼簡化一下就能夠看出:模塊化
//moduleA.js let goingta = "我是goingta"; module.exports = { goingta }; module.exports.fn = function() { goingta = "new goingta"; }; //index.js let obj = require("./moduleA.js"); obj.fn(); console.log("obj.goingta", obj.goingta);
最終結果輸出:"我是goingta"
從上面的結論咱們不可貴出,ES6 Module
和CommonJS
的本質區別:
1. 引用方式:CommonJS模塊輸出是值的拷貝,ES6 Module模塊輸出的值是引用
2. 時機:CommonJS是運行時加載,ES6 Module是編譯是輸出
差很少在6年前,當項目愈來愈大,用JS模擬劃分出來的類致使文件愈來愈多以及須要前置依賴的各類庫(那個時代的三叉戟jQuery
,Backbone
,Underscore
),模塊化以及各類腳手架開始興起,因而有了AMD
和CMD
以及當年這兩種規範之爭-AMD推崇依賴前置、提早執行,CMD
推崇依賴就近、延遲執行。AMD
的表明是require.js
,CMD
的表明是玉伯的Sea.js
AMD
規範是採用異步方式,依賴前置必須一開始就寫好,全部的依賴加載完成後纔會執行回調函數裏的內容:
// moduleB.js //一開始就要寫好這個模塊全部的依賴 define(["jQuery", "underscore", "moduleA"], function($, _) { if (false) { // 即使沒用到moduleA,也會被提早執行 moduleA.doSomething() } }); `CMD`規範按玉伯大大的原話`"是 Sea.JS 在推廣過程當中對模塊定義的規範化產出"`,而且當時在國內承認度很高。依賴就近書寫: // moduleB.js define(function(require, exports, module) { var moduleA = require('moduleA.js');//用到時才寫 moduleA..doSomething() //一堆其餘業務代碼 var $ = require('jquery.js'); $.xxxx() });
在07年左右正式有前端開發這個職位後(之前都是後端研發兼寫前端代碼),SEO、性能優化、語義模板、瀏覽器兼容、代碼混淆加密等等都須要前端開發承接是,每每是一個公用的base.js
外加幾個業務js放在html
裏面,而後用defer
和async
標記:
<script src="base.js" async></script> <script src="moduleA.js" defer></script>
defer
和async
的區別在於:defer
是「渲染完再執行」,async
是「下載完就執行」。