[修練之路-JS]2. JS and jQuery's Module Design Pattern

[修練之路-JS]2. JS and jQuery's Module Design Pattern

參考文件:Essential JavaScript And jQuery Design Patterns – A Free New Book, JavaScript Module Pattern: In-Depth

JavaScript 模組我們可以用類物件導向的方式來說明,

"封裝" :

在前一章中已經用過的"匿名closures"語法:

(function(){ //anonymous 
    var c = 10; // 私變數
}()); 
document.write(c); // 無法使用 c 變數

 

因為JavaScript在處理變數, 若沒有宣告var則為全域變數

(function(){ //anonymous function
    c = 13; // 全域變數    
})();
document.write(c); // 可以使用 c 變數

 

全域變數可能為造成封裝內容的程式發生問題, 故可以將他修改,

如: 全域變數jQuery 較 全域變數$ 效能佳, 故在下方的範例中直接將變更$修改為對照到全域變數jQuery, 而非全域變數$

(function($){ // $ = jQuery
    $('a[id="link"]'); // = jQuery('a[id="link"]');
})(jQuery);

 

預防沒有參數

    var m = (function(m){         
        m.p = 1; // 新增一個屬性
        m.f = function(){ return ++ m.p ; } ; // 新增一個方法, 註:要用c.p來存取屬性
        return m;
    }(m ||{})); // 預防沒有參數
    
    document.write(m.p + "<br />"); // 印出 1
    document.write(m.f()  + "<br />"); // 印出 2    

 

簡單的模組化(物件) 範例

var m = (function(){
    var c = {};    // 宣告一個物件
    c.p = 1; // 新增一個屬性
    c.f = function(){ return ++ c.p ; } ; // 新增一個方法, 註:要用c.p來存取屬性
    return c;
}());
document.write(m.p + "<br />"); // 印出 1
document.write(m.f()  + "<br />"); // 印出 2
 
// 另一種寫法
var m2 = (function(){
    var p = 1;    // 宣告私有屬性
    var f = function(){ return ++ p ; } ; // 新增一個私有方法
    
    return {
        p: p,
        f: f
    };
}());
document.write(m2.p + "<br />"); // 印出 1
document.write(m2.f()  + "<br />"); // 印出 2

 

做一個類似partial class

(function(){
    var m = (function(){ // partial class - main
        var c = {};    // 宣告一個物件
        c.p = 1; // 新增一個屬性
        c.f = function(){ return ++ c.p ; } ; // 新增一個方法, 註:要用c.p來存取屬性
        return c;
    }());
    
    extendtions(m); // 呼叫另一個partial class
    
    document.write(m.p + "<br />"); // 印出 1
    document.write(m.f()  + "<br />"); // 印出 2
    document.write(m.p2 + "<br />"); // 印出 2 , defined in partial class
    document.write(m.f2()  + "<br />"); // 印出 3 , defined in partial class
}());
 
 
function extendtions(arg_m){
    (function(m){  // partial class - second
        m.p2 = 2; // 新增一個屬性
        m.f2 = function() { return ++ m.p2; }; // 新增一個方法
        return m;
    }(arg_m));
}

 

"繼承"

    var parent = (function(){         
        var p = {};
        p.p = 1; // 新增一個屬性
        p.f = function(){ return ++ p.p ; } ; // 新增一個方法
        return p;
    }()); 
    var child = (function(p){
        var c = {}, key;
        for( key in p ){
            if(p.hasOwnProperty(key)){
                c[key] = p[key];
            }
        }
        c.f = function(){ return -- c.p };        
        return c;
    }(parent));
    
    document.write(parent.p + "<br />"); // 印出 1
    document.write(parent.f()  + "<br />"); // 印出 2
    document.write(child.p + "<br />"); // 印出 1
    document.write(child.f()  + "<br />"); // 印出 0

 

JavaScript 語法實在太活了, 還有很多進階的Module設計法, 因為比較少用, 就不繼續深究了.

 

以上的語法是用參數的方式來宣告, 若要用方式的方式宣告差別只在於

var obj = function(){
    var p = {};
    p.p = 1; // 新增一個屬性
    p.f = function(){ return ++ p.p ; } ; // 新增一個方法
    return p;
}; // 少一個括弧
document.write(new obj().p  + "<br />"); // 可以用new

 

再加碼一個jQuery plugin sample

(function($){
    $.fn.SayHello = function(name){        
        return this.each(function(){
            $(this).text('Hello ' + name); // 將每一個元素內部文字都改成Hello XXX
        });
    };
}(jQuery));
 
$(function(){
    $('a').SayHello('Hector'); // print 'Hello Hector'
});