<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      淺談 JavaScript 模塊化編程

      本博客同步自我的GitHub博客

      JavaScript本身不是一種模塊化語言,設計者在創造JavaScript之初應該也沒有想到這么一個腳本語言的作用領域會越來越大。以前一個頁面的JS代碼再多也不會多到哪兒去,而現在隨著越來越多的JavaScript庫和框架的出現,Single-page App的流行以及Node.js的迅猛發展,如果我們還不對自己的JS代碼進行一些模塊化的組織的話,開發過程會越來越困難,運行性能也會越來越低。因此,了解JS模塊化編程是非常重要的。

      簡單的模塊

      什么是模塊?我認為將不同功能的函數放在一起,組成一個能實現某種或某些特定功能的整體就是一個模塊,因此這樣:

      function add(a, b) {
        return a + b;
      }
      
      function divide(a, b) {
        return a / b;
      }
      

      如此簡單的兩個函數就可以組成一個模塊,這個模塊可以進行一些數學運算。

      當然沒有人會這么寫模塊。僅僅是從“型”上來看,兩個函數分散在全局環境中,這也看不出模塊的特點。模塊存在于全局變量中,應該提供一個命名空間,成為模塊內容的入口。那么我們可以將函數包裹在一個對象中:

      var math = {
        add: function(a, b) {
          return a + b;
        },
        divide: function(a, b) {
          return a / b;
        }
      }
      

      這樣看起來似乎有模塊的“型”了。但是這樣還不完善,math 中的所有成員都是對外暴露的,如果其中有一些變量不希望被修改的話那就有風險了。為了防止世界被破壞,為了維護私有變量不被修改,我們可以使用閉包。

      var math = (function() {
        var _flag = 0;
      
        return {
          add: function(a, b) {
            return a + b;
          },
          divide: function(a, b) {
            return a / b;
          }
        };
      })();
      

      外部代碼只能訪問返回的 adddivide 方法,內部的 _flag 變量是不能訪問的。關于創建對象的一些方法的解釋,可以參考我的另一篇博文,里面有較詳細的解釋。

      利用自執行函數的特點,我們還可以很方便地為模塊添加方法:

      var math = (function(module) {
        module.subtract = function(a, b) {
          return a - b;
        }
      })(math);
      

      模塊在全局變量中的名稱可能會與其他的模塊產生沖突,例如 $ 符號,雖然使用方便,但多個模塊可能都會用它作為自己的簡寫,例如jQuery。我們可以在模塊的組織代碼中用 $ 作為形參,將模塊的全名變量作為參數傳入,可起到防沖突的效果。

      var math = (function($) {
        // 這里的$指的就是Math
      })(math);
      

      模塊的構建思想便是通過這樣的方式逐漸演化而來,下面將通過介紹一些JS模塊化編程的標準來展示如何組織,管理和編寫模塊。

      AMDCMD

      在JavaScript模塊化編程的世界中,有兩個規范不得不提,它們分別是AMDCMD。現在的JS庫或框架,凡是模塊化的,一般都是遵循了這兩個規范其中之一。

      AMD(Asynchronous Module Definition)

      CommonJS
      在說AMD之前,先要提一下CommonJS。CommonJS是為了彌補JavaScript標準庫過少的缺點而產生的,由于JS沒有模塊機制(ES6引入了模塊系統,但瀏覽器全面支持估計還有好幾年),CommonJS就幫助JS實現模塊的功能。現在很熱門的Node.js就是CommonJS規范的一個實現。

      CommonJS在模塊中定義方法要借助一個全局變量 exports,它用來生成當前模塊的API:

      /* math module */
      
      exports.add = function(a, b) {
        return a + b;
      };
      

      要加載模塊就要使用CommonJS的一個全局方法 require()。加載之前實現的 math 模塊像這樣:

      var math = require('math');
      

      加載后 math 變量就是這個模塊對象的一個引用,要調用模塊中的方法就像調用普通對象的方法一樣了:

      var math = require('math');
      math.add(1, 3);
      

      總之,CommonJS就是一個模塊加載器,可以方便地對JavaScript代碼進行模塊化管理。但它也有缺點,它在設計之初并沒有完全為瀏覽器環境考慮,瀏覽器環境的特點是所有的資源,不考慮本地緩存的因素,都需要從服務器端加載,加載的速度取決于網絡速度,而CommonJS的模塊加載過程是同步阻塞的。也就是說如果 math 模塊體積很大,網速又不好的時候,整個程序便會停止,等待模塊加載完成。

      隨著瀏覽器端JS資源的體積越來越龐大,阻塞給體驗帶來的不良影響也越來越嚴重,終于從,在CommonJS社區中有了不同的聲音,AMD 規范誕生了。

      AMD
      它的特點便是異步加載,模塊的加載不會影響其他代碼的運行。所有依賴于某個模塊的代碼全部移到模塊加載語句的回調函數中去。AMD的 require() 語句接受兩個參數:

      // require([module], callback)
      require(['math'], function(math) {
        math.add(1, 3);
      });
      

      在回調函數中,可以通過 math 變量引用模塊。

      AMD規范也規定了模塊的定義規則,使用 define() 函數。

      define(id?, dependencies?, factory);
      

      它接受三個參數:
      id
      這是一個可選參數,相當于模塊的名字,加載器可通過id名加載對應的模塊。如果沒有提供id,加載器會將模塊文件名作為默認id。

      dependencies
      可選,接受一個數組參數,傳入當前對象依賴的對象id。

      factory
      回調函數,在依賴模塊加載完成后會調用,它的參數是所有依賴模塊的引用。回調函數的返回值就是當前對象的導出值。

      用AMD規范實現一個簡單的模塊可以這樣:

      define('foo', ['math'], function(math) {
        return {
          increase: function(x) {
            return math.add(x, 1);
          }
        };
      });
      

      如果省去id和dependencies參數的話,就是一個完全的匿名模塊。factory的參數將為默認值 requireexportsmodule 加載器將完全通過文件路徑的方式加載模塊,同時如果有依賴模塊的話可通過 require 方法加載。

      define(function(require, exports, module) {
        var math = require('math');
      
        exports.increase = function(x) {
          return math(x, 1);
        };
      });
      

      AMD規范也允許對加載進行一些配置,配置選項不是必須的,但靈活更改配置,會給開發帶來一些方便。

      baseUrl 以字符串形式規定根目錄的路徑,以后在加載模塊時都會以該路徑為標準。在瀏覽器中,工作目錄的路徑就是運行腳本的網頁所在的路徑。

      {
        baseUrl: './foo/bar'
      }
      

      path 可以指定需加載模塊的路徑,模塊名與路徑以鍵-值對的方式寫在對象中。如果一個模塊有多個可選地址,可以將這些地址寫在一個數組中。

      {
        path: {
          'foo': './bar'
        }
      }
      

      關于模塊路徑的設置項還有packagesmap

      shim
      對于某些沒有按照AMD規范編寫的模塊,比如jQuery,來說,要使它們能被加載器加載,需要用 shim 方法為其配置一些屬性。在 main 模塊中,用 require.config() 方法:

      require.config({
        shim: {
          'jquery': {
            exports: '$'
          },
          'foo': {
            deps: [
              'bar',
              'jquery'
            ],
            exports: 'foo'
          }
        }
      });
      

      之后再用加載器加載就可以了。

      目前實現了AMD規范的庫有很多,比較有名的是Require.js

      CMD(Common Module Definition)

      CMD在很多地方和AMD有相似之處,在這里我只說兩者的不同點。

      首先,CMD規范和CommonJS規范是兼容的,相比AMD,它簡單很多。遵循CMD規范的模塊,可以在Node.js中運行。

      define
      與AMD規范不同的是CMD規范中不使用 iddeps 參數,只保留 factory。其中:
      1.factory 接收對象/字符串時,表明模塊的接口就是對象/字符串。

      define({ 'foo': 'bar' });
      
      define('My name is classicemi.');
      

      define.cmd
      其值為一個空對象,用于判斷頁面中是否有CMD模塊加載器。

      if (typeof define === 'function' && define.cmd) {
        // 使用CMD模塊加載器編寫代碼
      }
      

      require
      此函數同樣用于獲取模塊接口。如需異步加載模塊,使用 require.async 方法。

      define(function(require, exports, module) {
        require.async('math', function(math) {
          math.add(1, 2);
        });
      });
      

      我們可以發現,require(id) 的寫法和CommonJS一樣是以同步方式加載模塊。要像AMD規范一樣異步加載模塊則使用 define.async 方法。

      exports
      此方法用于模塊對外提供接口。

      define(function(require, exports, module) {
        // 對外提供foo屬性
        exports.foo = 'bar';
      
        // 對外提供add方法
        exports.add = function(a, b) {
          return a + b;
        }
      });
      

      提供接口的另一個方法是直接return包含接口鍵值對的對象:

      define(function(require, exports, module) {
        return {
          foo: 'bar',
          add: function(a, b) {
            return a + b;
          }
        }
      });
      

      但是注意,不能用exports輸出接口對象:

      define(function(require, exports, module) {
        exports = {
          foo: 'bar',
          add: function(a, b) {
            return a + b;
          }
        }
      });
      

      這樣寫是錯誤的!
      替代方式是這樣寫:

      define(function(require, exports, module) {
        module.exports = {
          foo: 'bar',
          add: function(a, b) {
            return a + b;
          }
        }
      });
      

      之前錯誤的原因是在 factory 內部,exports 實際上是 module.exports 的一個引用,直接給 exports 賦值是不會改變 module.exports 的值的。

      在module對象上,除了有上面提到的 exports 以外,還有一些別的屬性和方法。
      module.id
      模塊的標識。

      define('math', [], function(require, exports, module) {
        // module.id 的值為 math
      });
      

      module.uri
      模塊的絕對路徑,由模塊系統解析得到。

      define(function(require, exports, module) {
        console.log(module.uri); // http://xxx.com/path/
      });
      

      module.dependencies
      值為一個數組,返回本模塊的依賴。

      Require.js 和 Sea.js

      之前在說AMD規范的時候提到了Require.js。它是AMD規范的代表性產品。另一個Sea.js在前端界也是赫赫有名了,CMD規范實際上就是它的產出。它們之間的區別也很能表現AMD和CMD規范之間的區別。

      AMD的依賴需要前置書寫

      define(['foo', 'bar'], function(foo, bar) {
        foo.add(1, 2);
        bar.subtract(3, 4);
      });
      

      CMD的依賴就近書寫即可,不需要提前聲明:
      同步式:

      define(function(require, exports, module) {
        var foo = require('foo');
        foo.add(1, 2);
        ...
        var bar = require('bar');
        bar.subtract(3, 4);
      });
      

      異步式:

      define(function(require, exports, module) {
        ...
        require.async('math', function(math) {
          math.add(1, 2);
        });
        ...
      });
      

      雖然AMD也可以用和CMD相似的方法,但不是官方推薦的。

      之前在介紹CMD的API時,我們可以發現其API職責專一,例如同步加載和異步加載的API都分為 requirerequire.async,而AMD的API比較多功能。

      總而言之,引用玉伯的總結:

      1. Require.js同時適用于瀏覽器端和服務器環境的模塊加載。Sea.js則專注于瀏覽器端的模塊加載實現。通過Node擴展也可以運行于Node環境中。
      2. Require.js -> AMD,Sea.js -> CMD。
      3. RequireJS 在嘗試讓第三方類庫修改自身來支持 RequireJS,目前只有少數社區采納。Sea.js 不強推,采用自主封裝的方式來“海納百川”,目前已有較成熟的封裝策略。
      4. Sea.js的調試工具比較完備,Require.js調試比較不方便。
      5. RequireJS 采取的是在源碼中預留接口的形式,插件類型比較單一。Sea.js 采取的是通用事件機制,插件類型更豐富。

      怎么看都像是在自夸啊= =,當然它有這個資格

      參考文獻

      1. CommonJS官網
      2. 阮一峰博客
      3. AMD Github
      4. CMD Github
      5. Sea.js
      6. Require.js
      posted @ 2014-10-09 09:49  吳雙Orange  閱讀(1384)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 一区二区丝袜美腿视频| 亚洲综合一区二区三区在线| 国产av一区二区三区综合| 91精品一区二区蜜桃| 99久久婷婷国产综合精品青草漫画| 讷河市| 中文字幕人妻有码久视频| 国产成人精品无缓存在线播放| 中文字幕久久六月色综合| 九九热精品在线视频观看| 午夜福利看片在线观看| 热久久美女精品天天吊色| 国产精品久久久一区二区三区| 久久精品免视看国产成人| 成人午夜免费无码视频在线观看| 久久香蕉国产线熟妇人妻| 性欧美老妇另类xxxx| 日本一区二区久久人妻高清| 蜜桃无码一区二区三区| 亚洲国产另类久久久精品小说| 变态另类视频一区二区三区| 国产不卡av一区二区| 国产高清在线精品一区APP| 国产精品无码dvd在线观看| 日韩av在线不卡一区二区三区| 日本一区二区三区四区黄色| 日韩高清亚洲日韩精品一区二区| 无码人妻丰满熟妇啪啪| 人妻熟妇乱又伦精品无码专区| 久久99精品久久99日本| 国产中文三级全黄| 休宁县| 亚洲精品美女久久久久9999| 人人妻人人玩人人澡人人爽| 蜜臀av久久国产午夜| 国产一区二区三区尤物视频| 国产肥臀视频一区二区三区| 亚洲qingse中文字幕久久| 国产资源精品中文字幕| 国产乱码精品一区二区三| 亚洲天堂久久一区av|