JavaScript PATTERNS
cHAPTER 5: 物件建立模式
如何建立一個物件
範例
let Obj= {
"name": "Ceall"
}
It's Easy !
大量使用時, 該注意甚麼
進階事項
- 命名空間
- 模組化
- private屬性與靜態成員觀念
oUTLINE
- 命名空間模式
- Private 屬性與方法
- 靜態成員
命名空間模式
一個原則
只建立一個全域變數, 其餘變數都是在該變數內
範例
// 全域變數
var MYAPP = {}
//變數
MYAPP.car = ''
// function
MYAPP.fn = function(){};
// Mudules
MYAPP.modules = {}
MYAP.modules.module1 = {}
MYAP.modules.module2 = {}
上述做法缺點
- 命名衝突
如何解決
- 採用命名空間函式
命名空間函式
var MYAPP = MYAPP || {};
MYAPP.namespace('MYAPP.a') // MYAPP.a
MYAPP.namespace('a.b.c') // MYAPP.a.b.c
MYAPP.namespace = function(ns_string){
let parts = ns_string.split("."),
parent = MYAPP,
i;
if(parts[0] === "MYAPP"){
parts = parts.slice(1)
}
for(i = 0; i < parts.length; i++){
if(typeof parent[parts[i]] === "undefined"){
parent[parts[i]] = {}
}
parent = parent[parts[i]]
}
return parent
}
原則: 若變數名稱存在, 則保留目前資料內容,
若不存在, 則建立一個空物件給予新變數
這樣就可以了, 嗎?
如果有100個變數, 可能會遇到
- 使用時, 需要打一長串的前綴名稱
- 任何一段code都可更動其他功能所使用的參數
- 變數名稱越長, 查詢時間越久
如何解決 ?
A: 沙盒模式
沙盒模式 - 核心概念
- 建立一個沙盒物件, 並設定初始的屬性與方法(sandbox)
- 該建構式可自行新增屬性與方法,並擴增到使用者建立的新沙盒中
- 可傳入一個回呼函式, 回呼函式預設會傳入沙盒物件, 透過回呼函式, 自行擴充新的變數名稱, 並可保護全域命名空間。
實做沙盒模式
function Sandbox(){
//將參數列轉為陣列
var args = Array.prototype.slice.call(arguments),
// 最後一個參數是callback function
callback = args.pop(),
// 模組可以用陣列方式傳遞, 也可以用個別參數傳入
modules = (args[0] && typeof args[0] === "string") ? args : args[0],
i;
// 先確保此函式是以建構式方式呼叫
if(!(this instanceof Sandbox)){
return new Sandbox(modules, callback);
}
// 依照需要為this增加屬性
this.a = 1;
this.b = 2;
// 現在,將模組新增至盒新的this物件
// 沒有指定模組, 或者"*"都表示「使用所有模組」
if(!modules || modules === '*'){
modules = [];
for(i in Sandbox.modules){
if(Sandbox.modules.hasOwnProperty(i)){
modules.push(i);
}
}
}
// 初始所需的模組
for(i = 0; i < modules.length; i += 1){
Sandbox.modules[modules[i]](this);
}
callback(this);
}
// 依照需要建立prototype的屬性
Sandbox.prototype = {
name: "My Application",
version: "1.0",
getName: function(){
return this.name;
}
};
簡單範例(1/2)
//沙盒模式 看起來像是
new Sandbox(function (box){
// 你的程式碼
// box是最初始的沙盒物件
})
// 使用擴增模組
Sandbox ('ajax','dom',function (box){
// 使用dom和ajax模組
// 此時沙盒物件, box, 已可使用'ajax', 'dom'兩個模組的屬性與方法
console.log(box);
})
Sandbox (['ajax', 'dom'], function (box){
console.log(box);
})
簡單範例(2/2)
// 建立沙盒模組
Sandbox.modules = {};
Sandbox.modules.dom = function (box){
box.geElement = function (){};
box.getStyle = function (){};
box.foo = "bar";
}
Sandbox.modules.ajax = function (box){
box.makeRequest = function (){};
box.getResponse = function (){};
}
Sandbox解決了
- 命名變數全部依賴在同一個全域變數
- 變數名稱過長, 階層太多
PRIVATE屬性與方法
js不像java一樣
沒有PRIVATE, pROTECT, PUBLIC可表示屬性與方法
所有的方法與屬性都是PUBLIC
pUBLIC範例
// public成員
var obj = {
prop: 1,
method: function(){
return "test"
}
}
console.log(obj.prop) //prop 可被public存取
console.log(obj.method()) //method 可被public存取
沒有private用法
可用closure實作
Private靜態成員
- 所有由同一個建構式建立的物件, 都可互相共享
- 建構式之外不可取用的成員
Private 建構式範例
// private建構式範例
function fn(){
// private成員
var data = 0
this.getData = function(){
return data
}
}
var test = new getData();
console.log(fn.data) // undefined, data是private
console.log(fn.getData) // 0, public方法可存取data
Private 物件實字範例
// private物件實字範例
var myData;
(function getData(){
// private成員
var data = 0
// 實作public
myData = {
// 特權方式
getData: function(){
return data
}
}
})()
myData.getData() // 0
特權方法
將PRIVATe成員RETURN到外部的變數
利用建構式產生PRIVATE變數的缺點
每次呼叫建構式產生新物件時, 都需要重新建立一次
使用頻繁的建構式, 可考慮改用Prototype
Prototype與隱私權
function Gadget(){
//private 成員
var name = 'iPod';
//public 方法
this.getName = function(){
return name;
}
}
Gadget.prototype = (function(){
//private成員
var browser = 'Mobile'
//public的prototype成員
return {
getBrowser: function(){
return browser
}
}
})()
var toy = new Gadget();
console.log(toy.getName()) // '自己的'特權方法
console.log(toy.getBrowser()) //prototype的特權方法
優點: 所有相同的建構式都可以共享prototype 內的屬性與方法, 節省記憶體
靜態成員
何謂靜態成員
- 不需建立實體即可使用
- 不會在實體與實體之間改變
靜態成員範例
//建構式
var Gadget = function(){}
//一個靜態方法
Gadget.isShiny = function(){
return "you bet";
}
//加入原型的方法
Gadget.prototype.setPrice = function(price){
tihs.price = price;
}
// 測試
//呼叫靜態方法
Gadget.isShiny(); // "you bet"
// 建立一個實體, 然後呼叫方法
var iphone = new Gadget();
iphone.setPrice(500);
typeof Gadget.setPrice; // "undefined", 無法用靜態方式呼叫實體方法
typeof iphone.isShiny; // "undefined", 無法實體呼叫靜態方法
JAVASCRIPT PATTERNS CHAPTER 5: 物件建立模式
By ceall
JAVASCRIPT PATTERNS CHAPTER 5: 物件建立模式
- 865