情境
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();
};