前端模塊化CommonJS慢洋、CMD塘雳、AMD、ES6

一普筹、CommonJS

????????Node.js是commonJS規(guī)范的主要實(shí)踐者粉捻,它有四個(gè)重要的環(huán)境變量為模塊化的實(shí)現(xiàn)提供支持:module、exports斑芜、require肩刃、global。實(shí)際使用時(shí)杏头,用module.exports定義當(dāng)前模塊對(duì)外輸出的接口(不推薦直接用exports)盈包,用require加載模塊。

  // 定義模塊math.js
  var basicNum = 0;

  function add(a, b) {
    return a + b;
  }
  module.exports = { //在這里寫(xiě)上需要向外暴露的函數(shù)醇王、變量
    add: add,
    basicNum: basicNum
  }

  // 引用自定義的模塊時(shí)呢燥,參數(shù)包含路徑寓娩,可省略.js
  var math = require('./math');
  math.add(2, 5);

  // 引用核心模塊時(shí)叛氨,不需要帶路徑
  var http = require('http');
  http.createService(...).listen(3000);

????????commonJS用同步的方式加載模塊。在服務(wù)端棘伴,模塊文件都存在本地磁盤(pán)寞埠,讀取非常快焊夸,所以這樣做不會(huì)有問(wèn)題仁连。但是在瀏覽器端,限于網(wǎng)絡(luò)原因阱穗,更合理的方案是使用異步加載饭冬。

二、AMD和require.js

????????AMD規(guī)范采用異步方式加載模塊揪阶,模塊的加載不影響它后面語(yǔ)句的運(yùn)行昌抠,所有依賴這個(gè)模塊的語(yǔ)句,都定義在一個(gè)回調(diào)函數(shù)中鲁僚,等到加載完成之后炊苫,這個(gè)回調(diào)函數(shù)才會(huì)運(yùn)行,這里介紹用require.js實(shí)現(xiàn)AMD規(guī)范的模塊化蕴茴,用require.config()指定引用路徑等劝评,用define()定義模塊,用require()加載模塊倦淀;
????????首先我們需要引入require.js文件和一個(gè)入口文件main.js蒋畜,main.js中配置require.config()并規(guī)定項(xiàng)目中用到的基礎(chǔ)模塊;

/** 網(wǎng)頁(yè)中引入require.js及main.js **/
<script src="js/require.js" data-main="js/main"></script>
 
/** main.js 入口文件/主模塊 **/
// 首先用config()指定各模塊路徑和引用名
require.config({
  baseUrl: "js/lib",
  paths: {
    "jquery": "jquery.min",  //實(shí)際路徑為js/lib/jquery.min.js
    "underscore": "underscore.min",
  }
});
// 執(zhí)行基本操作
// 引用模塊的時(shí)候撞叽,我們將模塊名放在[]中作為reqiure()的第一參數(shù)姻成;如果我們定義的模塊本身也依賴其他模塊,那就需要將它們放在[]中作為define()的第一參數(shù);
require(["jquery","underscore"],function($,_){
  // some code here
});
// 定義math.js模塊
define(function () {
    var basicNum = 0;
    var add = function (x, y) {
        return x + y;
    };
    return {
        add: add,
        basicNum :basicNum
    };
});
// 定義一個(gè)依賴underscore.js的模塊
define(['underscore'],function(_){
  var classify = function(list){
    _.countBy(list,function(num){
      return num > 30 ? 'old' : 'young';
    })
  };
  return {
    classify :classify
  };
})
 
// 引用模塊插龄,將模塊放在[]內(nèi)
require(['jquery', 'math'],function($, math){
  var sum = math.add(10,20);
  $("#sum").html(sum);
});

三、CMD

????????require.js在申明依賴的模塊時(shí)會(huì)在第一之間加載并執(zhí)行模塊內(nèi)的代碼:CMD是另一種js模塊化方案科展,它與AMD很類似均牢,不同點(diǎn)在于:AMD 推崇依賴前置、提前執(zhí)行才睹,CMD推崇依賴就近徘跪、延遲執(zhí)行。此規(guī)范其實(shí)是在sea.js推廣過(guò)程中產(chǎn)生的琅攘。

/** AMD寫(xiě)法 **/
define(["a", "b", "c", "d", "e", "f"], function(a, b, c, d, e, f) { 
     // 等于在最前面聲明并初始化了要用到的所有模塊
    a.doSomething();
    if (false) {
        // 即便沒(méi)用到某個(gè)模塊 b垮庐,但 b 還是提前執(zhí)行了
        b.doSomething()
    } 
});
 
/** CMD寫(xiě)法 **/
define(function(require, exports, module) {
    var a = require('./a'); //在需要時(shí)申明
    a.doSomething();
    if (false) {
        var b = require('./b');
        b.doSomething();
    }
});
 
/** sea.js **/
// 定義模塊 math.js
define(function(require, exports, module) {
    var $ = require('jquery.js');
    var add = function(a,b){
        return a+b;
    }
    exports.add = add;
});
// 加載模塊
seajs.use(['math.js'], function(math){
    var sum = math.add(1+2);
});

四、ES6

????????ES6在語(yǔ)言標(biāo)準(zhǔn)的層面上坞琴,實(shí)現(xiàn)了模塊功能哨查,而且實(shí)現(xiàn)得相當(dāng)簡(jiǎn)單,旨在成為瀏覽器和服務(wù)器通用的模板解決方案剧辐,其模塊功能主要由兩個(gè)命令構(gòu)成:export和import寒亥,export命令用于規(guī)定模塊的對(duì)外接口,import命令用于輸入其他模塊提供的功能荧关;使用import命令的時(shí)候溉奕,用戶需要知道所要加載的變量名或函數(shù)名,其實(shí)ES6還提供了export default命令羞酗,為模塊指定默認(rèn)輸出腐宋,對(duì)應(yīng)的import語(yǔ)句不需要使用大括號(hào),這也更趨近于ADM的引用寫(xiě)法檀轨;ES6的模塊不是對(duì)象,import命令會(huì)被 JavaScript 引擎靜態(tài)分析欺嗤,在編譯時(shí)就引入模塊代碼参萄,而不是在代碼運(yùn)行時(shí)加載,所以無(wú)法實(shí)現(xiàn)條件加載煎饼。也正因?yàn)檫@個(gè)讹挎,使得靜態(tài)分析成為可能;

/** 定義模塊 math.js **/
var basicNum = 0;
var add = function (a, b) {
    return a + b;
};
export { basicNum, add };
 
/** 引用模塊 **/
import { basicNum, add } from './math';
function test(ele) {
    ele.textContent = add(99 + basicNum);
}
/** export default **/
//定義輸出
export default { basicNum, add };
//引入
import math from './math';
function test(ele) {
    ele.textContent = math.add(99 + math.basicNum);
}

五吆玖、 ES6 模塊與 CommonJS 模塊的差異

1. CommonJS 模塊輸出的是一個(gè)值的拷貝筒溃,ES6 模塊輸出的是值的引用。

  • CommonJS 模塊輸出的是值的拷貝沾乘,也就是說(shuō)怜奖,一旦輸出一個(gè)值,模塊內(nèi)部的變化就影響不到這個(gè)值翅阵。
  • ES6 模塊的運(yùn)行機(jī)制與 CommonJS 不一樣歪玲。JS 引擎對(duì)腳本靜態(tài)分析的時(shí)候迁央,遇到模塊加載命令import,就會(huì)生成一個(gè)只讀引用滥崩。等到腳本真正執(zhí)行時(shí)岖圈,再根據(jù)這個(gè)只讀引用,到被加載的那個(gè)模塊里面去取值钙皮。換句話說(shuō)蜂科,ES6 的import有點(diǎn)像 Unix 系統(tǒng)的“符號(hào)連接”,原始值變了短条,import加載的值也會(huì)跟著變导匣。因此,ES6 模塊是動(dòng)態(tài)引用慌烧,并且不會(huì)緩存值逐抑,模塊里面的變量綁定其所在的模塊。

2. CommonJS 模塊是運(yùn)行時(shí)加載屹蚊,ES6 模塊是編譯時(shí)輸出接口厕氨。

  • 運(yùn)行時(shí)加載: CommonJS 模塊就是對(duì)象;即在輸入時(shí)是先加載整個(gè)模塊汹粤,生成一個(gè)對(duì)象命斧,然后再?gòu)倪@個(gè)對(duì)象上面讀取方法,這種加載稱為“運(yùn)行時(shí)加載”嘱兼。

  • 編譯時(shí)加載: ES6 模塊不是對(duì)象国葬,而是通過(guò) export 命令顯式指定輸出的代碼,import時(shí)采用靜態(tài)命令的形式芹壕。即在import時(shí)可以指定加載某個(gè)輸出值汇四,而不是加載整個(gè)模塊,這種加載稱為“編譯時(shí)加載”踢涌。

CommonJS 加載的是一個(gè)對(duì)象(即module.exports屬性)通孽,該對(duì)象只有在腳本運(yùn)行完才會(huì)生成。而 ES6 模塊不是對(duì)象睁壁,它的對(duì)外接口只是一種靜態(tài)定義背苦,在代碼靜態(tài)解析階段就會(huì)生成

參考鏈接:前端模塊化:CommonJS,AMD,CMD,ES6

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市潘明,隨后出現(xiàn)的幾起案子行剂,更是在濱河造成了極大的恐慌,老刑警劉巖钳降,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件厚宰,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡牲阁,警方通過(guò)查閱死者的電腦和手機(jī)固阁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)壤躲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人备燃,你說(shuō)我怎么就攤上這事碉克。” “怎么了并齐?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵漏麦,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我况褪,道長(zhǎng)撕贞,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任测垛,我火速辦了婚禮捏膨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘食侮。我一直安慰自己号涯,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布锯七。 她就那樣靜靜地躺著链快,像睡著了一般。 火紅的嫁衣襯著肌膚如雪眉尸。 梳的紋絲不亂的頭發(fā)上域蜗,一...
    開(kāi)封第一講書(shū)人閱讀 50,084評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音噪猾,去河邊找鬼霉祸。 笑死,一個(gè)胖子當(dāng)著我的面吹牛袱蜡,可吹牛的內(nèi)容都是我干的脉执。 我是一名探鬼主播,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼戒劫,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了婆廊?” 一聲冷哼從身側(cè)響起迅细,我...
    開(kāi)封第一講書(shū)人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎淘邻,沒(méi)想到半個(gè)月后茵典,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡宾舅,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年统阿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了彩倚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡扶平,死狀恐怖帆离,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情结澄,我是刑警寧澤哥谷,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布,位于F島的核電站麻献,受9級(jí)特大地震影響们妥,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜勉吻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一监婶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧齿桃,春花似錦惑惶、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至踩娘,卻和暖如春刮刑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背养渴。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工雷绢, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人理卑。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓翘紊,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親藐唠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子帆疟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容