前端模塊化之CommonJS,ES6,AMD,CMD

最近在搞跨平臺解決方案,討論關於模塊劃分的問題以及如何儘可能多的複用邏輯代碼。因而就有了此文章,以前的博客也寫過,不過因爲主機商跑路,寶貴的資源也就沒了,說多了都是淚~ 這裏按模塊化發展的歷史回溯的時間序html

一. ES6 Moudle

這個是目前前端小夥伴接觸的最多的,是瀏覽器和服務端通用的模塊化解決方案,主要命令爲:exportimport。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

CommonJS最主要的表明就是Node.js,主要命令:moduleexportsrequire。其中有個使人疑惑的點是exportsmodule.exports,其實理解起來也很簡單,就是在模塊裏面加了一句: exports = module.exports = {}; exportsmodule.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的區別

從上面的結論咱們不可貴出,ES6 ModuleCommonJS的本質區別:

1. 引用方式:CommonJS模塊輸出是值的拷貝,ES6 Module模塊輸出的值是引用
2. 時機:CommonJS是運行時加載,ES6 Module是編譯是輸出

四. 模塊化歷史

差很少在6年前,當項目愈來愈大,用JS模擬劃分出來的類致使文件愈來愈多以及須要前置依賴的各類庫(那個時代的三叉戟jQueryBackboneUnderscore),模塊化以及各類腳手架開始興起,因而有了AMDCMD以及當年這兩種規範之爭-AMD推崇依賴前置、提早執行,CMD推崇依賴就近、延遲執行。AMD的表明是require.jsCMD的表明是玉伯的Sea.js

五. AMD和CMD

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裏面,而後用deferasync標記:

<script src="base.js" async></script>

<script src="moduleA.js" defer></script>

deferasync的區別在於:defer是「渲染完再執行」,async是「下載完就執行」。

相關文章
相關標籤/搜索