- Singleton 的概念是讓特定的 class 只有唯一的實體
- 當第二次使用同一個 class 建立物件,會得到和第一次建立時相同的物件
使用物件實字建立物件
var obj = {
myProp: 1
};
var obj1 = {
myProp: 1
};
obj === obj1; // false
每次使用物件實字建立物件,其實都是在建立 singleton,就算建立了相同的內容與成員,這兩個物件也不會相等
實現方式
- 用全域變數儲存實體
- 缺點:非常容易被覆蓋掉,千萬不要使用這種方式
- 用建構式的靜態屬性儲存實體
- 缺點:有機會被更動,但機率比全域變數來得低
- 用 closure 的特性儲存實體
- 優點:實體為 private,無法在建構式外修改
- 缺點:儲存在記憶體空間
儲存在靜態屬性中的實體
function Universe() {
// 判斷是否已有現有的實體
if (typeof Universe.instance === "object") {
return Universe.instance;
}
this.startTime = 0;
this.bang = "Big";
// 快取
Universe.instance = this;
}
var uni1 = new Universe();
var uni2 = new Universe(); // uni2 會得到相同的 instance
// 缺點,有機會被異動
Universe.instance = {foo: 'bye'};
var uni3 = new Universe();
uni1 === uni3; // false
儲存在 Closure 中的實體
作法一
function Universe() {
var instance = this; // 快取的實體
this.startTime = 0;
// 重新定義建構式
Universe = function() {
return instance;
}
}
var uni = new Universe();
var uni2 = new Universe();
uni === uni2; // true
缺點,重新定義的函式會失去之前定義的屬性
function Universe() {
var instance = this; // 快取的實體
this.startTime = 0;
// 重新定義建構式
Universe = function() {
return instance;
}
}
Universe.prototype.nothing = true;
var uni = new Universe();
Universe.prototype.everything = true;
var uni2 = new Universe();
uni.nothing; // true
uni.everything; // true
uni2.nothing; // undefined
uni2.everything; // undefined
uni.constructor.name; // Universe
uni.constructor === Universe; // false
作法二:書中建議的做法,使用立即函式包住建構式與實體
var Universe;
(function() {
var instance;
Universe = function() {
if (instance) {
return instance; // 第二次呼叫建構式則回傳 private 的 instance
}
instance = this; // 第一次呼叫建構式會建立一個物件,並指派給 instance
this.startTime = 0;
};
})();