Jak*_*old 287 javascript singleton design-patterns function
在JavaScript中实现单例模式的最简单/最简洁的方法是什么?
CMS*_*CMS 304
我认为最简单的方法是声明一个简单的对象文字:
var myInstance = {
method1: function () {
// ...
},
method2: function () {
// ...
}
};
Run Code Online (Sandbox Code Playgroud)
如果您想在单例实例上使用私有成员,可以执行以下操作:
var myInstance = (function() {
var privateVar = '';
function privateMethod () {
// ...
}
return { // public interface
publicMethod1: function () {
// all private members are accesible here
},
publicMethod2: function () {
}
};
})();
Run Code Online (Sandbox Code Playgroud)
这就是所谓的模块模式,它基本上可以让你来封装对象私有成员,通过采取利用的优势关闭.
seb*_*eli 166
我认为最干净的方法是这样的:
var SingletonFactory = (function(){
function SingletonClass() {
//do stuff
}
var instance;
return {
getInstance: function(){
if (instance == null) {
instance = new SingletonClass();
// Hide the constructor so the returned object can't be new'd...
instance.constructor = null;
}
return instance;
}
};
})();
Run Code Online (Sandbox Code Playgroud)
之后,您可以调用该函数
var test = SingletonFactory.getInstance();
Run Code Online (Sandbox Code Playgroud)
zzz*_*Bov 101
我不确定我是否同意将模块模式用作单例模式的替代品.我经常看到在完全没有必要的地方使用和滥用单身人士,我确信模块模式填补了程序员否则会使用单例的许多空白,但模块模式不是单例.
var foo = (function () {
"use strict";
function aPrivateFunction() {}
return { aPublicFunction: function () {...}, ... };
}());
Run Code Online (Sandbox Code Playgroud)
Foo声明时,模块模式中初始化的所有内容都会发生.此外,模块模式可用于初始化构造函数,然后可以多次实例化该构造函数.虽然模块模式是许多工作的正确工具,但它并不等同于单例.
var Foo = function () {
"use strict";
if (Foo._instance) {
//this allows the constructor to be called multiple times
//and refer to the same instance. Another option is to
//throw an error.
return Foo._instance;
}
Foo._instance = this;
//Foo initialization code
};
Foo.getInstance = function () {
"use strict";
return Foo._instance || new Foo();
}
Run Code Online (Sandbox Code Playgroud)
长形式,使用模块模式
var Foo = (function () {
"use strict";
var instance; //prevent modification of "instance" variable
function Singleton() {
if (instance) {
return instance;
}
instance = this;
//Singleton initialization code
}
//instance accessor
Singleton.getInstance = function () {
return instance || new Singleton();
}
return Singleton;
}());
Run Code Online (Sandbox Code Playgroud)
在我提供的两个版本的Singleton模式中,构造函数本身可以用作访问器:
var a,
b;
a = new Foo(); //constructor initialization happens here
b = new Foo();
console.log(a === b); //true
Run Code Online (Sandbox Code Playgroud)
如果您不习惯使用构造函数,则可以在if (instance)语句中抛出错误,并坚持使用long形式:
var a,
b;
a = Foo.getInstance(); //constructor initialization happens here
b = Foo.getInstance();
console.log(a === b); //true
Run Code Online (Sandbox Code Playgroud)
我还要提一下,单例模式非常适合隐式构造函数模式:
function Foo() {
if (Foo._instance) {
return Foo._instance;
}
//if the function wasn't called as a constructor,
//call it as a constructor and return the result
if (!(this instanceof Foo)) {
return new Foo();
}
Foo._instance = this;
}
var f = new Foo(); //calls Foo as a constructor
-or-
var f = Foo(); //also calls Foo as a constructor
Run Code Online (Sandbox Code Playgroud)
Utk*_*pta 42
在ES6 中,正确的方法是:
class MyClass {
constructor() {
if (MyClass._instance) {
throw new Error("Singleton classes can't be instantiated more than once.")
}
MyClass._instance = this;
// ... Your rest of the constructor code goes after this
}
}
var instanceOne = new MyClass() // Executes succesfully
var instanceTwo = new MyClass() // Throws errorRun Code Online (Sandbox Code Playgroud)
或者,如果您不希望在创建第二个实例时抛出错误,您可以只返回最后一个实例,如下所示:
class MyClass {
constructor() {
if (MyClass._instance) {
return MyClass._instance
}
MyClass._instance = this;
// ... Your rest of the constructor code goes after this
}
}
var instanceOne = new MyClass()
var instanceTwo = new MyClass()
console.log(instanceOne === instanceTwo) // Logs "true"Run Code Online (Sandbox Code Playgroud)
iaf*_*rek 31
如果您正在使用,node.JS那么您可以利用node.JS 缓存机制和您的Singleton将非常简单:
class Singleton {\n constructor() {\n this.message = \'I am an instance\';\n }\n}\nmodule.exports = new Singleton();\nRun Code Online (Sandbox Code Playgroud)\n请注意,我们导出的不是类而是实例 Singleton Singleton()。
Node.JS 每次需要时都会缓存并重用相同的对象。
\n更多详情请查看:Node.JS 和 Singleton 模式
\nXaq*_*ron 14
在es6:
class Singleton {
constructor () {
if (!Singleton.instance) {
Singleton.instance = this
}
// Initialize object
return Singleton.instance
}
// Properties & Methods
}
const instance = new Singleton()
Object.freeze(instance)
export default instance
Run Code Online (Sandbox Code Playgroud)
小智 12
如果你想使用类:
class Singleton {
constructor(name, age) {
this.name = name;
this.age = age;
if(this.constructor.instance)
return this.constructor.instance;
this.constructor.instance = this;
}
}
let x = new Singleton('s', 1);
let y = new Singleton('k', 2);
Run Code Online (Sandbox Code Playgroud)
上述输出将是:
console.log(x.name, x.age, y.name, y.age) // s 1 s 1
Run Code Online (Sandbox Code Playgroud)
使用函数编写单例的另一种方法
function AnotherSingleton (name,age) {
this.name = name;
this.age = age;
if(this.constructor.instance)
return this.constructor.instance;
this.constructor.instance = this;
}
let a = new AnotherSingleton('s', 1);
let b = new AnotherSingleton('k', 2);
Run Code Online (Sandbox Code Playgroud)
上述输出将是:
console.log(a.name, a.age, b.name, b.age) // s 1 s 1
Run Code Online (Sandbox Code Playgroud)
小智 7
皮肤猫的方法不止一种:根据您的品味或具体需要,您可以应用任何建议的解决方案.我个人尽可能地去找CMS的第一个解决方案(当你不需要隐私时).既然问题是关于最简单和最干净的,那就是胜利者.甚至:
var myInstance = {}; // done!
Run Code Online (Sandbox Code Playgroud)
这(引自我的博客)......
var SingletonClass = new function() {
this.myFunction() {
//do stuff
}
this.instance = 1;
}
Run Code Online (Sandbox Code Playgroud)
没有多大意义(我的博客示例也没有)因为它不需要任何私有变量,所以它几乎相同:
var SingletonClass = {
myFunction: function () {
//do stuff
},
instance: 1
}
Run Code Online (Sandbox Code Playgroud)
我弃用了我的答案,看到我的另一个.
通常模块模式(参见CMS的答案)不是单例模式就足够了.然而,单例的一个特征是它的初始化被延迟直到需要对象.模块模式缺少此功能.
我的主张(CoffeeScript):
window.singleton = (initializer) ->
instance = undefined
() ->
return instance unless instance is undefined
instance = initializer()
Run Code Online (Sandbox Code Playgroud)
在JavaScript中编译为:
window.singleton = function(initializer) {
var instance;
instance = void 0;
return function() {
if (instance !== void 0) {
return instance;
}
return instance = initializer();
};
};
Run Code Online (Sandbox Code Playgroud)
然后我可以做以下事情:
window.iAmSingleton = singleton(function() {
/* This function should create and initialize singleton. */
alert("creating");
return {property1: 'value1', property2: 'value2'};
});
alert(window.iAmSingleton().property2); // "creating" will pop up; then "value2" will pop up
alert(window.iAmSingleton().property2); // "value2" will pop up but "creating" will not
window.iAmSingleton().property2 = 'new value';
alert(window.iAmSingleton().property2); // "new value" will pop up
Run Code Online (Sandbox Code Playgroud)
对我来说,最简单/最干净的方式也意味着简单地理解,没有像 Java 版本的讨论中所讨论的那样花哨的东西:
从我的角度来看,最适合最简单/最干净的答案是:
乔纳森对在 Java 中实现单例模式的有效方法是什么的回答?
并且它只能部分转换为 JavaScript。JavaScript 的一些不同之处在于:
但考虑到最新的 ECMA 语法,有可能接近:
class Singleton {
constructor(field1,field2) {
this.field1=field1;
this.field2=field2;
Singleton.instance=this;
}
static getInstance() {
if (!Singleton.instance) {
Singleton.instance=new Singleton('DefaultField1','DefaultField2');
}
return Singleton.instance;
}
}
Run Code Online (Sandbox Code Playgroud)
示例用法
console.log(Singleton.getInstance().field1);
console.log(Singleton.getInstance().field2);
Run Code Online (Sandbox Code Playgroud)
DefaultField1
DefaultField2
Run Code Online (Sandbox Code Playgroud)
使用 ES6 类和私有静态字段。调用 Singleton 类的新实例将返回相同的实例。实例变量也是私有的,不能在类外部访问。
class Singleton {
// # is a new Javascript feature that denotes private
static #instance;
constructor() {
if (!Singleton.#instance) {
Singleton.#instance = this
}
return Singleton.#instance
}
get() {
return Singleton.#instance;
}
}
const a = new Singleton();
const b = new Singleton();
console.log(a.get() === b.get()) // true
console.log(Singleton.instance === undefined) // true
Run Code Online (Sandbox Code Playgroud)
因为JavaScript的非阻塞性,JavaScript中的Singletons在使用中真的很难看.全局变量在没有所有这些回调的情况下也会通过整个应用程序为您提供一个实例,模块模式轻轻地隐藏在接口后面的内部.见@CMS答案.
但是,既然你想要一个单身......
var singleton = function(initializer) {
var state = 'initial';
var instance;
var queue = [];
var instanceReady = function(createdInstance) {
state = 'ready';
instance = createdInstance;
while (callback = queue.shift()) {
callback(instance);
}
};
return function(callback) {
if (state === 'initial') {
state = 'waiting';
queue.push(callback);
initializer(instanceReady);
} else if (state === 'waiting') {
queue.push(callback);
} else {
callback(instance);
}
};
};
Run Code Online (Sandbox Code Playgroud)
用法:
var singletonInitializer = function(instanceReady) {
var preparedObject = {property: 'value'};
// calling instanceReady notifies singleton that instance is ready to use
instanceReady(preparedObject);
}
var s = singleton(singletonInitializer);
// get instance and use it
s(function(instance) {
instance.doSomething();
});
Run Code Online (Sandbox Code Playgroud)
单身人士通过整个应用程序为您提供的不仅仅是一个实例:他们的初始化被推迟到第一次使用.当你处理初始化很昂贵的对象时,这真的很重要.昂贵通常意味着I/O和JavaScript I/O总是意味着回调.
不要相信给你界面的答案instance = singleton.getInstance(),他们都错过了重点.
如果他们在实例准备就绪时不进行回调,那么当初始化程序执行I/O时它们将无法工作.
是的,回调总是比函数调用看起来更丑,它立即返回对象实例.但同样:当你做I/O时,回调是强制性的.如果你不想做任何I/O,那么实例化在程序启动时就足够便宜了.
var simpleInitializer = function(instanceReady) {
console.log("Initializer started");
instanceReady({property: "initial value"});
}
var simple = singleton(simpleInitializer);
console.log("Tests started. Singleton instance should not be initalized yet.");
simple(function(inst) {
console.log("Access 1");
console.log("Current property value: " + inst.property);
console.log("Let's reassign this property");
inst.property = "new value";
});
simple(function(inst) {
console.log("Access 2");
console.log("Current property value: " + inst.property);
});
Run Code Online (Sandbox Code Playgroud)
在这个例子中setTimeout伪造了一些昂贵的I/O操作.这说明了为什么JavaScript中的单例真的需要回调.
var heavyInitializer = function(instanceReady) {
console.log("Initializer started");
var onTimeout = function() {
console.log("Initializer did his heavy work");
instanceReady({property: "initial value"});
};
setTimeout(onTimeout, 500);
};
var heavy = singleton(heavyInitializer);
console.log("In this example we will be trying");
console.log("to access singleton twice before it finishes initialization.");
heavy(function(inst) {
console.log("Access 1");
console.log("Current property value: " + inst.property);
console.log("Let's reassign this property");
inst.property = "new value";
});
heavy(function(inst) {
console.log("Access 2. You can see callbacks order is preserved.");
console.log("Current property value: " + inst.property);
});
console.log("We made it to the end of the file. Instance is not ready yet.");
Run Code Online (Sandbox Code Playgroud)
我从JavaScript模型中获得了这个例子使用编码和设计模式构建更好的应用程序通过Stoyan Stefanov的书,如果你需要一些简单的实现类,如singltone对象,你可以使用立即函数如下:
var ClassName;
(function() {
var instance;
ClassName = function ClassName() {
//If private instance variable already initialized return reference
if(instance) {
return instance;
}
//If instance does not created save pointer of original reference
//to private instance variable.
instance = this;
//All constructor initialization will be here
// i.e.:
this.someProperty = 0;
this.someMethod = function() {
//Some action here
};
};
}());
Run Code Online (Sandbox Code Playgroud)
您可以通过以下测试用例来检查此示例:
//Extending defined class like Singltone object using new prototype property
ClassName.prototype.nothing = true;
var obj_1 = new ClassName();
//Extending defined class like Singltone object using new prototype property
ClassName.prototype.everything = true;
var obj_2 = new ClassName();
//Testing does this two object pointing to same instance
console.log(obj_1 === obj_2); //Result is true, it points to same instance object
//All prototype properites work
//no matter when they were defined
console.log(obj_1.nothing && obj_1.everything
&& obj_2.nothing && obj_2.everything); //Result true
//Values of properties which is defined inside of constructor
console.log(obj_1.someProperty);// output 0
console.log(obj_2.someProperty);// output 0
//Changing property value
obj_1.someProperty = 1;
console.log(obj_1.someProperty);// output 1
console.log(obj_2.someProperty);// output 1
console.log(obj_1.constructor === ClassName); //Output true
Run Code Online (Sandbox Code Playgroud)
这种方法传递所有测试用例,而私有静态实现将在使用原型扩展时失败(可以修复但不简单),并且由于实例暴露给公众,公共静态实现不太可取.
小智 6
以下在节点v6中起作用
class Foo {
constructor(msg) {
if (Foo.singleton) {
return Foo.singleton;
}
this.msg = msg;
Foo.singleton = this;
return Foo.singleton;
}
}
Run Code Online (Sandbox Code Playgroud)
我们测试:
const f = new Foo('blah');
const d = new Foo('nope');
console.log(f); // => Foo { msg: 'blah' }
console.log(d); // => Foo { msg: 'blah' }
Run Code Online (Sandbox Code Playgroud)
Christian C. Salvadó和zzzzBov 的回答都给出了很好的答案,但只是基于我从 PHP/Zend Framework 进入重度 Node.js 开发的基础上添加我自己的解释,其中单例模式很常见。
以下注释记录代码基于以下要求:
我的代码与 zzzzBov 的答案非常相似,除了我在构造函数中添加了一个原型链和更多注释,这些注释应该可以帮助那些来自 PHP 或类似语言的人将传统的 OOP 转换为 JavaScript 的原型性质。它可能不是“最简单”的,但我相信它是最合适的。
// Declare 'Singleton' as the returned value of a self-executing anonymous function
var Singleton = (function () {
"use strict";
// 'instance' and 'constructor' should not be available in a "public" scope
// here they are "private", thus available only within
// the scope of the self-executing anonymous function
var _instance=null;
var _constructor = function (name) {
this.name = name || 'default';
}
// Prototypes will be "public" methods available from the instance
_constructor.prototype.getName = function () {
return this.name;
}
// Using the module pattern, return a static object
// which essentially is a list of "public static" methods
return {
// Because getInstance is defined within the same scope
// it can access the "private" 'instance' and 'constructor' vars
getInstance:function (name) {
if (!_instance) {
console.log('creating'); // This should only happen once
_instance = new _constructor(name);
}
console.log('returning');
return _instance;
}
}
})(); // Self execute
// Ensure 'instance' and 'constructor' are unavailable
// outside the scope in which they were defined
// thus making them "private" and not "public"
console.log(typeof _instance); // undefined
console.log(typeof _constructor); // undefined
// Assign instance to two different variables
var a = Singleton.getInstance('first');
var b = Singleton.getInstance('second'); // passing a name here does nothing because the single instance was already instantiated
// Ensure 'a' and 'b' are truly equal
console.log(a === b); // true
console.log(a.getName()); // "first"
console.log(b.getName()); // Also returns "first" because it's the same instance as 'a'
Run Code Online (Sandbox Code Playgroud)
请注意,从技术上讲,自执行匿名函数本身就是一个单例,正如 Christian C. Salvadó 提供的代码中所展示的那样。这里唯一的问题是,当构造函数本身是匿名的时,不可能修改构造函数的原型链。
请记住,对于 JavaScript,“公共”和“私有”的概念不像在 PHP 或 Java 中那样适用。但是我们通过利用 JavaScript 的功能范围可用性规则实现了相同的效果。
你可以这样做:
var singleton = new (function() {
var bar = 123
this.foo = function() {
// Whatever
}
})()
Run Code Online (Sandbox Code Playgroud)
我想我找到了最简洁的JavaScript编程方式,但你需要一些想象力.我从"javascript the good parts"一书中的一种工作技术中得到了这个想法.
您可以创建一个这样的类,而不是使用new关键字:
function Class()
{
var obj = {}; // Could also be used for inheritence if you don't start with an empty object.
var privateVar;
obj.publicVar;
obj.publicMethod= publicMethod;
function publicMethod(){}
function privateMethod(){}
return obj;
}
Run Code Online (Sandbox Code Playgroud)
您可以通过以下方式实例化上述对象:
var objInst = Class(); // !!! NO NEW KEYWORD
Run Code Online (Sandbox Code Playgroud)
现在考虑到这种工作方法,你可以创建一个像这样的单例:
ClassSingleton = function()
{
var instance= null;
function Class() // This is the class like the above one
{
var obj = {};
return obj;
}
function getInstance()
{
if( !instance )
instance = Class(); // Again no new keyword;
return instance;
}
return { getInstance : getInstance };
}();
Run Code Online (Sandbox Code Playgroud)
现在您可以通过调用获取您的实例
var obj = ClassSingleton.getInstance();
Run Code Online (Sandbox Code Playgroud)
我认为这是最好的方式,因为完整的"类"甚至无法访问.
最清楚的答案应该是 Addy Osmani 所著的《学习 JavaScript 设计模式》一书中的这个答案。
var mySingleton = (function () {
// Instance stores a reference to the singleton
var instance;
function init() {
// Singleton
// Private methods and variables
function privateMethod(){
console.log( "I am private" );
}
var privateVariable = "I'm also private";
var privateRandomNumber = Math.random();
return {
// Public methods and variables
publicMethod: function () {
console.log( "The public can see me!" );
},
publicProperty: "I am also public",
getRandomNumber: function() {
return privateRandomNumber;
}
};
};
return {
// Get the singleton instance if one exists
// or create one if it doesn't
getInstance: function () {
if ( !instance ) {
instance = init();
}
return instance;
}
};
})();Run Code Online (Sandbox Code Playgroud)
这就是我使用 ES6 功能实现单例模式的方法。是的,我知道这看起来不像面向对象的方法,但我发现这种方法很容易实现,而且是一种干净的实现方式。
const Singleton = (() => {
var _instance = !_instance && new Object('Object created....');
return () => _instance;
})();
//************************************************************************
var instance1 = Singleton();
var instance2 = Singleton();
console.log(instance1 === instance2); // true
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
123683 次 |
| 最近记录: |