[JavaScript] 類別物件寫法 (建構&靜態物件) – Class Object Coding Style (constructor & static class)

情境

JavaScript如何達到靜態類別設計?

https://github.com/yidas/js-design-patterns/blob/master/class/


Constructor Class

var Class = function (options) {
    this.render = function () {}
};

var object1 = new Class();
object1.render(); 

Literals Object

JavaScript靜態物件的第一個想法,

var Class =  {
    render : function () {}
};

Class.render(); 

架構不錯,缺點為在物件內無法宣告區域變數(亦即達不到private變數或方法)。
若在物件方法中再次用到function,且須使用this指到物件本身就會有瓶頸,得每次帶入物件‵this‵本身,而無法從物件那層定義個物件區域變數代表this


Static Class

目前我靜態物件的最佳解

var Class = new function (options) {
    var self = this;
    var construtor = function() {}
    this.render = function() {}
    construtor();
};

Class.render(); 

此寫法支援宣告區域變數,以補足Literals Object的缺點:

函式包裝回傳物件寫法(function(){})()

另一種直接生成寫法,但須透過return this取得物件。

var Class = (function (options) {
    this.render = function () {}
    return this;
})();

Class.render();

ADDITION

Use Strict

JavaScript Use Strict(嚴謹模式)建議使用在物件撰寫中。

This 傳遞

this傳遞問題解決方法:

定義class self區域變數為this

var Class = new function (options) {
    var self = this;
    this.render = function() {}
    var init = function() {
        self.render();
    }
    init();
};

意即所有Class內部均透過self區域變數呼叫Class本身,保留內部巢狀this使用彈性。

Bind This

var Class = new function (options) {
    var self = this;
    this.render = function() {}
    var init = (function() {
        this.render();
    }).bind(this);
    init();
};

使用Bind方法將Class級this傳遞進去取代內部this,微升效能但每次須使用得各自宣告。


完整範例

/** 
 * Class
 *
 * Each object load data only one time, the data source could be given by 
 * options or load from given AJAX URL automatically. You can render multiple 
 * items you designed by different options.
 *
 * Author   Nick Tsai <myintaer@gmail.com>
 * Version  
 */
var Class = function (options) {

    "user strict";

    /* Private Propertites */

    // Create self constant in class
    var self = this;

    // initialize options parameter for definition
    var o = options || {};

    // Flag for loadData()
    var isLoading = false;


    /* Public Propertites */

    // Tree data
    self.data = o.data || null;

    // AJAX URL for loadData()
    self.ajaxUrl = o.ajaxUrl || '/org3layermenu/ajax';


    /* Constructor */
    var __constructor = function () {

        // Construct code
    }

    /* <public method> Initialize with callback function */
    self.init = function (callback) {

        loadData(callback);
    }

    /* <public method> Render */
    self.render = function (options) {

        // Load data if no data 
        if (self.data===null) {

            loadData(function() {
                self.render(options)
            });

            return;
        }

        console.log(self.data);

        // Render code
    }

    /* <private method> Load data from AJAX */
    var loadData = function (callback) {

        // Check if is loading
        if (isLoading) {

            // Retry later
            setTimeout(function(){

                callback();
            }, 500);

            return;
        }

        isLoading = true;

        // Load data by AJAX
        $.get( self.ajaxUrl, function(data) {

            self.data = data;

            isLoading = false;

            callback();
        });
    }

    // Activate constructor
    __constructor();
}

ControllerApp範例

單Route的Javascript設計模式提供參考:

$(document).ready(function() {

    ControllerNameApp.run();
});

/** 
 * @author Nick Tsai <myintaer@gmail.com>
 */
var ControllerNameApp = new function() {

    var self = this;

    // Flag for add or edit
    self.editSN = 0;

    var __construct = function() {

    };

    // Run the App
    self.run = function() {

        // Register events
        listeners();

        // Load Data Table
        loadData();

        // Initialize gov select
        $('select[name=gov_area]').change();
    }

    var listeners = function() {

        $('input[name=status]').change(function() {

            // code..
        });
    };

    var loadData = function() {

        // Catch outer variable example
        var url = viewData.ajaxUrl.index;

        // Get data by AJAX
        $.get(url, function(res) {

            if (res.code==200 && res.data) {

                // Render
                $.each(res.data, function(key, row) {

                    // render table code..
                });
            } 

        }, 'json')
            .error(function(xhr, ajaxOptions, thrownError) {

                console.log(thrownError)
            });
    };

    __construct();
};

Leave a Reply

Your email address will not be published. Required fields are marked *