<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          前端模塊化:CommonJS,AMD,CMD,ES6 學(xué)習(xí)

          共 4397字,需瀏覽 9分鐘

           ·

          2020-08-24 16:23

          作者 | subwaydown
          地址 |?https://juejin.im/post/6844903576309858318

          模塊化的開發(fā)方式可以提高代碼復(fù)用率,方便進行代碼的管理。通常一個文件就是一個模塊,有自己的作用域,只向外暴露特定的變量和函數(shù)。目前流行的js模塊化規(guī)范有CommonJS、AMD、CMD以及ES6的模塊系統(tǒng)。參見阮一峰老師的文章?module-loader[1]?。

          一、CommonJS

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

          //?定義模塊math.js
          var?basicNum?=?0;
          function?add(a,?b)?{
          ??return?a?+?b;
          }
          module.exports?=?{?//在這里寫上需要向外暴露的函數(shù)、變量
          ??add:?add,
          ??basicNum:?basicNum
          }

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

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

          commonJS用同步的方式加載模塊。在服務(wù)端,模塊文件都存在本地磁盤,讀取非常快,所以這樣做不會有問題。但是在瀏覽器端,限于網(wǎng)絡(luò)原因,更合理的方案是使用異步加載。

          二、AMD和require.js

          AMD規(guī)范采用異步方式加載模塊,模塊的加載不影響它后面語句的運行。所有依賴這個模塊的語句,都定義在一個回調(diào)函數(shù)中,等到加載完成之后,這個回調(diào)函數(shù)才會運行。這里介紹用require.js實現(xiàn)AMD規(guī)范的模塊化:用require.config()指定引用路徑等,用define()定義模塊,用require()加載模塊。

          首先我們需要引入require.js文件和一個入口文件main.js。main.js中配置require.config()并規(guī)定項目中用到的基礎(chǔ)模塊。

          /**?網(wǎng)頁中引入require.js及main.js?**/


          /**?main.js?入口文件/主模塊?**/
          //?首先用config()指定各模塊路徑和引用名
          require.config({
          ??baseUrl:?"js/lib",
          ??paths:?{
          ????"jquery":?"jquery.min",??//實際路徑為js/lib/jquery.min.js
          ????"underscore":?"underscore.min",
          ??}
          });
          //?執(zhí)行基本操作
          require(["jquery","underscore"],function($,_){
          ??//?some?code?here
          });

          引用模塊的時候,我們將模塊名放在[]中作為reqiure()的第一參數(shù);如果我們定義的模塊本身也依賴其他模塊,那就需要將它們放在[]中作為define()的第一參數(shù)。

          //?定義math.js模塊
          define(function?()?{
          ????var?basicNum?=?0;
          ????var?add?=?function?(x,?y)?{
          ????????return?x?+?y;
          ????};
          ????return?{
          ????????add:?add,
          ????????basicNum?:basicNum
          ????};
          });
          //?定義一個依賴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和sea.js

          require.js在申明依賴的模塊時會在第一之間加載并執(zhí)行模塊內(nèi)的代碼:

          define(["a",?"b",?"c",?"d",?"e",?"f"],?function(a,?b,?c,?d,?e,?f)?{?
          ????//?等于在最前面聲明并初始化了要用到的所有模塊
          ????if?(false)?{
          ??????//?即便沒用到某個模塊?b,但?b?還是提前執(zhí)行了
          ??????b.foo()
          ????}?
          });

          CMD是另一種js模塊化方案,它與AMD很類似,不同點在于:AMD 推崇依賴前置、提前執(zhí)行,CMD推崇依賴就近、延遲執(zhí)行。此規(guī)范其實是在sea.js推廣過程中產(chǎn)生的。

          /**?AMD寫法?**/
          define(["a",?"b",?"c",?"d",?"e",?"f"],?function(a,?b,?c,?d,?e,?f)?{?
          ?????//?等于在最前面聲明并初始化了要用到的所有模塊
          ????a.doSomething();
          ????if?(false)?{
          ????????//?即便沒用到某個模塊?b,但?b?還是提前執(zhí)行了
          ????????b.doSomething()
          ????}?
          });

          /**?CMD寫法?**/
          define(function(require,?exports,?module)?{
          ????var?a?=?require('./a');?//在需要時申明
          ????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 Module

          ES6 在語言標準的層面上,實現(xiàn)了模塊功能,而且實現(xiàn)得相當(dāng)簡單,旨在成為瀏覽器和服務(wù)器通用的模塊解決方案。其模塊功能主要由兩個命令構(gòu)成:export和import。export命令用于規(guī)定模塊的對外接口,import命令用于輸入其他模塊提供的功能。

          /**?定義模塊?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);
          }

          如上例所示,使用import命令的時候,用戶需要知道所要加載的變量名或函數(shù)名。其實ES6還提供了export default命令,為模塊指定默認輸出,對應(yīng)的import語句不需要使用大括號。這也更趨近于ADM的引用寫法。

          /**?export?default?**/
          //定義輸出
          export?default?{?basicNum,?add?};
          //引入
          import?math?from?'./math';
          function?test(ele)?{
          ????ele.textContent?=?math.add(99?+?math.basicNum);
          }

          復(fù)制代碼ES6的模塊不是對象,import命令會被 JavaScript 引擎靜態(tài)分析,在編譯時就引入模塊代碼,而不是在代碼運行時加載,所以無法實現(xiàn)條件加載。也正因為這個,使得靜態(tài)分析成為可能。

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

          1. CommonJS 模塊輸出的是一個值的拷貝,ES6 模塊輸出的是值的引用。

          CommonJS 模塊輸出的是值的拷貝,也就是說,一旦輸出一個值,模塊內(nèi)部的變化就影響不到這個值。ES6 模塊的運行機制與 CommonJS 不一樣。JS 引擎對腳本靜態(tài)分析的時候,遇到模塊加載命令import,就會生成一個只讀引用。等到腳本真正執(zhí)行時,再根據(jù)這個只讀引用,到被加載的那個模塊里面去取值。換句話說,ES6 的import有點像 Unix 系統(tǒng)的“符號連接”,原始值變了,import加載的值也會跟著變。因此,ES6 模塊是動態(tài)引用,并且不會緩存值,模塊里面的變量綁定其所在的模塊。

          2. CommonJS 模塊是運行時加載,ES6 模塊是編譯時輸出接口。

          運行時加載: CommonJS 模塊就是對象;即在輸入時是先加載整個模塊,生成一個對象,然后再從這個對象上面讀取方法,這種加載稱為“運行時加載”。

          編譯時加載: ES6 模塊不是對象,而是通過 export 命令顯式指定輸出的代碼,import時采用靜態(tài)命令的形式。即在import時可以指定加載某個輸出值,而不是加載整個模塊,這種加載稱為“編譯時加載”。

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

          最后

          1.看到這里了就點個在看支持下吧,你的在看是我創(chuàng)作的動力。

          2.關(guān)注公眾號程序員成長指北「帶你一起學(xué)Node」

          3.我是kaola?,可以添加我的微信【ikoala520】,拉你進技術(shù)交流群一起學(xué)習(xí)。


          “在看轉(zhuǎn)發(fā)”是最大的支持

          瀏覽 41
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日日国产爽 | 爱爱网址银 | 蜜臀久久99精品久久久久老师 | 一区二区视频在线 | 麻豆av无码久久精品 |