所以我希望有一个名为client
的课程,它将成为我用JavaScript编写的视频游戏的基础。
client
应该是一个只能有一个实例的类,但它的第一个创建应该由我自己在特定事件中设置,例如当用户单击“开始”按钮时。
我让自己变成了一个单独的类,我开始卸载它只是为了测试:
// Singleton class for the client
var client = (function() {
// Public methods
var _this = {
construct: function() {
delete _this.construct;
_this.director = new lime.Director(document.body, window.innerWidth, window.innerHeight); // Setup the rendering engine
}
}
return _this;
})();
// Fire when dependencies are loaded
window.onload = client.construct;
问题:
但我打算将其作为一个开源项目,在最后一行client.construct
似乎是一个非常不寻常的约定。如何编写我的单例类,以便用new Client
构造它并且永远不能再构造它?
答案 0 :(得分:7)
首先:你确定你真的想这样做吗?对于大多数简单的情况,您可能最好不要使用prototype
或完全使用new
关键字,而只需使用您想要的属性和方法编写对象文字 - 或者创建一个具有一次性功能的对象,如果需要稍微复杂的构造逻辑。简单就是好。
我想有几种情况你可能想在JavaScript中创建一个“传统的”单例,比如延迟实例化,或者如果你使用classical inheritance涉及你的单例类的原型。
在这种情况下,您可能希望尝试这种基于bfavaretto的方法,在该方法中,类的用户应通过调用Client.getSingletonInstance()
而不是new Client()
来获取Client对象,并且new
方法内部通过getSingletonInstance()
实例化客户端。
var Client = (function() {
// Our "private" instance
var instance;
// The constructor
function Client() {
// If it's being called again, throw an error
if (typeof instance != "undefined") {
throw new Error("Client can only be instantiated once.");
}
// initialize here
// Keep a closured reference to the instance
instance = this;
}
// Add public methods to Client.prototype
Client.prototype.myPublic = function() {
}
Client.getSingletonInstance = function() {
if (typeof instance == "undefined") {
return new this();
}
else {
return instance;
}
}
// Return the constructor
return Client;
})();
var c1 = Client.getSingletonInstance();
var c2 = Client.getSingletonInstance();
console.log(c1 == c2); // true
我更喜欢这种方式,因为在我看来,让类的用户调用new
但实际上没有获得新对象会产生误导。
答案 1 :(得分:3)
您可以使用在常规面向对象语言中使用的相同模式:将实例存储在“私有”或“静态”属性中(我引用这些术语是因为它们不能精确地应用于JavaScript) 。在代码中,这将是这样的,使用“私有”属性来存储实例(“静态”属性将是构造函数的属性):
var Client = (function() {
// Our "private" instance
var instance;
// The constructor
function Client() {
// If it's being called again, return the singleton instance
if(typeof instance != "undefined") return instance;
// initialize here
// Keep a closured reference to the instance
instance = this;
}
// Add public methods to Client.prototype
Client.prototype.myPublic = function() {
}
// Return the constructor
return Client;
})();
var c1 = new Client();
var c2 = new Client();
console.log(c1 == c2); // true
答案 2 :(得分:1)
这样的事情:
var Client = (function ClientClass(){
var instance;
// Constructor
function Client() {
if (instance) throw 'Already instantiated';
this.director = new lime.Director(...);
instance = true;
}
Client.prototype = {
// Public methods
};
return Client;
}());
答案 3 :(得分:0)
这可能是你想要的:
var initialized = false;
function initialize() {
if (!initialized) {
window.client = new Client();
initialized = true;
}
}
window.onload = initialize;
答案 4 :(得分:0)
你没有。在强类型语言中,单例是通过使用私有构造函数并公开包含该类的唯一实例的静态属性来创建的。你可以做的唯一防止第二次实例化的是抛出异常,但这甚至是更糟糕的设计。但是,您可以延迟实例化对象:
// A wrapper function
var client = (function () {
var client = function() {
// Actual class
}
var instance = null;
// Property to return the instance
Object.defineProperty("instance", {
get: function () {
if (!instance) { instance = new client(); }
return instance;
}
}
return client;
})();
答案 5 :(得分:0)
这是我最喜欢的单例实例模式,它简单明了:
var mySingleton = new function() {
// ...
}
所以你可以这样做:
var myClient = new function() {
this.director = null;
this.initialize = function() {
// Setup the rendering engine
this.director = new lime.Director(
document.body,
window.innerWidth,
window.innerHeight
);
}
}
window.onload = myClient.initialize();