js庫寫法

來源:互聯網
上載者:User

標籤:

前言:

  現在javascript庫特別多,其寫法各式各樣,總結幾種我們經常見到的,作為自己知識的積累。而目前版本的 JavaScript 並未提供一種原生的、語言層級的模組化組織模式,而是將模組化的方法交由開發人員來實現。因此,出現了很多種 JavaScript 模組化的實現方式,

以 AMD 為例,該規範使用 define 函數來定義模組。

define(factory(){    //模組化});

 

模組模式:

模組模式使用了 JavaScript 的一個特性,即閉包(Closures)。現今流行的一些 JS 庫中經常見到以下形式的代碼:

;(function (參數) {  // 模組代碼  // return something;})(參數);

上面的代碼定義了一個匿名函數,並立即調用自己。

也有一些開發人員在函數運算式前面加上一個驚歎號(!)或分號(;),而不是用括弧包起來。

!function (參數) {  // 代碼  // return something}(參數);

還有些人喜歡用括弧將整個 IIFE 圍起來,這樣就變成了以下的形式:

(function (參數) {  // 代碼  // return something}(參數));
參數輸入:

JavaScript 有一個特性叫做隱式全域變數(implied globals),當使用一個變數名時,JavaScript 解譯器將反向遍曆範圍鏈來尋找變數的聲明,如果沒有找到,就假定該變數是全域變數。這種特性使得我們可以在閉包裡隨處引用全域變數,比如 jQuery 或 window。然而,這是一種不好的方式。

考慮模組的獨立性和封裝,對其它對象的引用應該通過參數來引入。如果模組內需要使用其它全域對象,應該將這些對象作為參數來顯式引用它們,而非在模組內直 接引用這些對象的名字。以 jQuery 為例,若在參數中沒有輸入 jQuery 對象就在模組內直接引用 $ 這個對象,是有出錯的可能的。正確的方式大致應該是這樣的:

;(function ($, w) {  // $ is jQuery  // w is window  // 局部變數及代碼  // 返回})(jQuery, window);
模組輸出(Module Export)

有時我們不只是要使用全域變數,我們也要聲明和輸出模組中的對象,這可以通過匿名函數的 return 語句來達成,而這也構成了一個完整的模組模式。

var klm= (function () {    var myklm = {},        modeval= 1;     function privateMethod() {        // ...    }     myklm.moduleProperty = 1;    mymyklm.moduleMethod = function () {        // ...    };     return myklm ;}());

這段代碼聲明了一個變數 MODULE,它帶有兩個可訪問的屬性:moduleProperty 和 moduleMethod,其它的代碼都封裝在閉包中保持著私人狀態。參考以前提過的參數輸入,我們還可以通過參數引用其它全域變數。

輸出簡單對象:

使用對象直接量來表達 JavaScript 對象是很常見的。比如:var x = { p1: 1, p2: "2", f: function(){ /*... */ } }

var Module1 = (function () {  var private_variable = 1;  function private_method() { /*...*/ }   var my = {    property1: 1,    property2: private_variable,    method1: private_method,    method2: function () {        // ...    }  };  return my;}());
輸出函數:

有時候我們希望返回的並不是一個對象,而是一個函數。有兩種需求要求我們返回一個函數,一種情況是我們需要它是一個函數,比如 jQuery,它是一個函數而不是一個簡單對象;另一種情況是我們需要的是一個“類”而不是一個直接量,之後我們可以用 "new" 來執行個體它。目前版本的 JavaScript 並沒有專門的“類”定義,但它卻可以通過 function 來表達。

var klm= (function () {  // 私人成員及代碼 ...   return function(name) {    this.name = name;    this.bark = function() { /*...*/ }  };}()); var com = new klm("蒯靈敏");com.bark();

前面已經提到一種形式是輸出對象直接量(Object Literal Notation),而 Revealing Module Pattern 其實就是這種形式,只是做了一些限定。這種模式要求在私人範圍內中定義變數和函數,然後返回一個匿名對象,在該對象中指定要公開的成員。

var klm= (function () {  // 私人變數及函數  var x = 1;  function f1() {}  function f2() {}   return {    public_method1: f1,    public_method2: f2  };}());
擴充:緊耦合擴充:

有時我們要求在擴充時調用以前已被定義的方法,這也有可能被用於覆蓋已有的方法。這時,對模組的定義順序是有要求的。

var klm = (function (my) {  var old_moduleMethod = my.moduleMethod;   my.moduleMethod = function () {    // 方法重載    // 可通過 old_moduleMethod 調用以前的方法...  };  return my;}(klm));
複製與繼承:
var MODULE_TWO = (function (old) {    var my = {},        key;     for (key in old) {        if (old.hasOwnProperty(key)) {            my[key] = old[key];        }    }     var super_moduleMethod = old.moduleMethod;    my.moduleMethod = function () {        // override method on the clone, access to super through super_moduleMethod    };     return my;}(MODULE));

上面代碼再精簡一下:可以使用 Object.create()

var MODULE_TWO = (function (old) {  var my = Object.create(old);   var super_moduleMethod = old.moduleMethod;  my.moduleMethod = function () {    // override method ...  };   return my;}(MODULE));
 與其它模組規範或 JS 庫的適配:模組環境探測:

現今,CommonJS Modules 與 AMD 有著廣泛的應用,如果確定 AMD 的 define 是可用的,我們當然可以使用 define 來編寫模組化的代碼。然而,我們不能假定我們的代碼必然運行於 AMD 環境下,有沒有辦法可以讓我們的代碼?

其實我們只需要在某個地方加上對 CommonJS Modules 與 AMD 的探測並根據探測結果來“註冊”自己就可以了,以上那些模組模式仍然有用。AMD 定義了 define 函數,我們可以使用 typeof 探測該函數是否已定義。若要更嚴格一點,可以繼續判斷 define.amd 是否有定義。另外,SeaJS 也使用了 define 函數,但和 AMD 的 define 又不太一樣。對於 CommonJS,可以檢查 exports 或是 module.exports 是否有定義。

var klm = (function () {  var my = {};  // 代碼 ...   if (typeof define == ‘function‘) {    define( function(){ return my; } );  }else if (typeof module != ‘undefined‘ && module.exports) {    module.exports = my;  }  return my;}());
其它一些 JS 庫的做法

jquery的檢測方式

if ( typeof module === "object" && module && typeof module.exports === "object" ) {    module.exports = jQuery;} else {    if ( typeof define === "function" && define.amd ) {        define( "jquery", [], function () { return jQuery; } );    }} if ( typeof window === "object" && typeof window.document === "object" ) {    window.jQuery = window.$ = jQuery;}

接下來看看多重匿名函數的做法:

(function (root, factory) {  if (typeof exports === "object" && exports) {    factory(exports); // CommonJS  } else {    var mustache = {};    factory(mustache);    if (typeof define === "function" && define.amd) {      define(mustache); // AMD    } else {      root.Mustache = mustache; // <script>    }  }}(this, function (mustache) {  // 模組主要的代碼放在這兒});

這段代碼與前面介紹的方式不太一樣,它使用了兩個匿名函數。後面那個函數可以看作是模組代碼的工廠函數,它是模組的主體部分。前面那個函數對運行環境進行 檢測,根據檢測的結果對模組的工廠函數進行調用。另外,作為一個通用庫,它並沒使用 window 對象,而是使用了 this,因為在簡單的函數調用中,this 其實就是全域對象。

再看看 doT 的做法

(function() {    "use strict";     var doT = {        version: ‘1.0.0‘,        templateSettings: { /*...*/ },        template: undefined, //fn, compile template        compile:  undefined  //fn, for express    };     if (typeof module !== ‘undefined‘ && module.exports) {        module.exports = doT;    } else if (typeof define === ‘function‘ && define.amd) {        define(function(){return doT;});    } else {        (function(){ return this || (0,eval)(‘this‘); }()).doT = doT;    }    // ...}());

這段代碼裡的 (0, eval)(‘this‘) 是一個小技巧,這個運算式用來得到 Global 對象,‘this‘ 其實是傳遞給 eval 的參數,但由於 eval 是經由 (0, eval) 這個運算式間接得到的,因此 eval 將會在全域對象範圍中尋找 this,結果得到的是全域對象。若是代碼運行於瀏覽器中,那麼得到的其實是 window 對象。

 

JavaScript 模組化的未來

尚在制定中的 ES 6 會對模組作出語言層級的定義。我們來看一個執行個體,以下的程式碼片段摘自“ES6:JavaScript中將會有的幾個新東西”

module Car {   // 內部變數  var licensePlateNo = ‘556-343‘;   // 暴露到外部的變數和函數  export function drive(speed, direction) {     console.log(‘details:‘, speed, direction);   }   export module engine{     export function check() { }   }   export var miles = 5000;   export var color = ‘silver‘; };

在以後自己寫js封裝的時候上面是我參考的資料,繼續激情的前進著。。。

js庫寫法

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.