Qual é a maneira mais simples / limpa de implementar o padrão singleton em JavaScript?
Qual é a maneira mais simples / limpa de implementar o padrão singleton em JavaScript?
Respostas:
Eu acho que a maneira mais fácil é declarar um simples objeto literal:
var myInstance = {
method1: function () {
// ...
},
method2: function () {
// ...
}
};
Se você deseja membros privados em sua instância singleton, pode fazer algo assim:
var myInstance = (function() {
var privateVar = '';
function privateMethod () {
// ...
}
return { // public interface
publicMethod1: function () {
// all private members are accessible here
},
publicMethod2: function () {
}
};
})();
Isto tem sido chamado o padrão de módulo , que basicamente permite que você encapsular membros privados em um objeto, aproveitando-se o uso de fechamentos .
UPDATE: Gostaria de acrescentar que, se você quiser impedir a modificação do objeto singleton, poderá congelá-lo usando o ES5Object.freeze
método .
Isso tornará o objeto imutável, impedindo qualquer modificação em sua estrutura e valores.
Além disso, gostaria de mencionar que, se você estiver usando o ES6, poderá representar um singleton usando os Módulos do ES com muita facilidade e pode manter um estado privado declarando variáveis no escopo do módulo :
// my-singleton.js
const somePrivateState = []
function privateFn () {
// ...
}
export default {
method1() {
// ...
},
method2() {
// ...
}
}
Então você pode simplesmente importar o objeto singleton para usá-lo:
import myInstance from './my-singleton.js'
// ...
publicMethod1
chamaria publicMethod2
?
getInstance
método estático e um construtor privado -, mas IMO, essa é a maneira mais "simples" de criar um objeto singleton em Javascript, e no final ele atende ao mesmo objetivo - um único objeto, que você não pode inicializar novamente (não há construtor, é apenas um objeto) -. Sobre o código vinculado, ele tem alguns problemas, trocar as a
e b
variável declarações e teste a === window
. Felicidades.
Eu acho que a abordagem mais limpa é algo como:
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;
}
};
})();
Depois, você pode chamar a função como
var test = SingletonFactory.getInstance();
delete instance.constructor
:x = SingletonClass.getInstance();delete x.constructor;new x.constructor;
Não tenho certeza se concordo com o padrão do módulo sendo usado como substituto de um padrão singleton. Eu sempre vi singletons usados e abusados em lugares onde eles são totalmente desnecessários, e tenho certeza que o padrão do módulo preenche muitas lacunas onde os programadores usariam um singleton, mas o padrão do módulo não é um singleton.
var foo = (function () {
"use strict";
function aPrivateFunction() {}
return { aPublicFunction: function () {...}, ... };
}());
Tudo inicializado no padrão do módulo acontece quando Foo
é declarado. Além disso, o padrão do módulo pode ser usado para inicializar um construtor, que pode ser instanciado várias vezes. Embora o padrão do módulo seja a ferramenta certa para muitos trabalhos, não é equivalente a um singleton.
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();
}
formato longo, usando o padrão do módulo
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;
}());
Nas duas versões do padrão Singleton que eu forneci, o próprio construtor pode ser usado como o acessador:
var a,
b;
a = new Foo(); //constructor initialization happens here
b = new Foo();
console.log(a === b); //true
Se você não se sentir confortável usando o construtor dessa maneira, poderá gerar um erro na if (instance)
instrução e continuar usando o formulário longo:
var a,
b;
a = Foo.getInstance(); //constructor initialization happens here
b = Foo.getInstance();
console.log(a === b); //true
Também devo mencionar que o padrão singleton se ajusta bem ao padrão implícito da função construtora:
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
var singleton = {}
não se encaixa nessa definição.
var singleton = {}
é como você implementa o singleton em Javascript .
Em 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
instance
campo. Como está atualmente ( instance
definida como this
), essa classe também pode ter outros campos e o congelamento não faz sentido.
O seguinte funciona no nó v6
class Foo {
constructor(msg) {
if (Foo.singleton) {
return Foo.singleton;
}
this.msg = msg;
Foo.singleton = this;
return Foo.singleton;
}
}
Testamos:
const f = new Foo('blah');
const d = new Foo('nope');
console.log(f); // => Foo { msg: 'blah' }
console.log(d); // => Foo { msg: 'blah' }
No ES6, a maneira correta de fazer isso é:
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 error
Ou, se você não deseja que um erro seja gerado na criação da segunda instância, basta retornar a última instância, assim:
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"
instance
e _instance
. É apenas uma convenção de nomenclatura nas linguagens de programação que denominamos variáveis privadas anexadas com um sublinhado. Eu suspeito que a razão para o seu código não funcionar é que você está usando em this.instance
vez deMyClass.instance
Existem mais de uma maneira de esfolar um gato :) Dependendo do seu gosto ou necessidade específica, você pode aplicar qualquer uma das soluções propostas. Pessoalmente, busco a primeira solução do CMS sempre que possível (quando você não precisa de privacidade). Como a pergunta era sobre a mais simples e a mais limpa, esse é o vencedor. Ou até:
var myInstance = {}; // done!
Isso (citação do meu blog) ...
var SingletonClass = new function() {
this.myFunction() {
//do stuff
}
this.instance = 1;
}
não faz muito sentido (o exemplo do meu blog também não) porque não precisa de vars particulares, portanto é praticamente o mesmo que:
var SingletonClass = {
myFunction: function () {
//do stuff
},
instance: 1
}
this.f(){}
Eu reprovo minha resposta, vejo minha outra .
Normalmente, o padrão do módulo (consulte a resposta do CMS), que NÃO é padrão singleton, é bom o suficiente. No entanto, um dos recursos do singleton é que sua inicialização é atrasada até que o objeto seja necessário. O padrão do módulo não possui esse recurso.
Minha proposta (CoffeeScript):
window.singleton = (initializer) ->
instance = undefined
() ->
return instance unless instance is undefined
instance = initializer()
O que foi compilado em JavaScript:
window.singleton = function(initializer) {
var instance;
instance = void 0;
return function() {
if (instance !== void 0) {
return instance;
}
return instance = initializer();
};
};
Então eu posso fazer o seguinte:
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
Devido à natureza não-bloqueadora do JavaScript, Singletons em JavaScript são realmente feios em uso. As variáveis globais também fornecerão uma instância por todo o aplicativo, sem todos esses retornos de chamada; o padrão do módulo oculta suavemente os internos por trás da interface. Consulte a resposta @CMS.
Mas, desde que você queria um singleton ...
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);
}
};
};
Uso:
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();
});
Os singletons oferecem mais do que apenas uma instância em todo o aplicativo: a inicialização é adiada até o primeiro uso. Isso é realmente importante quando você lida com objetos cuja inicialização é cara. Caro geralmente significa E / S e, em JavaScript, E / S sempre significam retornos de chamada.
Não confie em respostas que lhe dão uma interface instance = singleton.getInstance()
, pois todas elas não entendem.
Se eles não aceitarem que o retorno de chamada seja executado quando a instância estiver pronta, eles não funcionarão quando o inicializador fizer E / S.
Sim, os retornos de chamada sempre parecem mais feios que a chamada de função, que retorna imediatamente a instância do objeto. Mas, novamente: quando você faz E / S, os retornos de chamada são obrigatórios. Se você não deseja fazer nenhuma E / S, a instanciação é barata o suficiente para fazê-lo no início do programa.
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);
});
Neste exemplo, setTimeout
falsifica algumas operações caras de E / S. Isso ilustra por que os singletons em JavaScript realmente precisam de retornos de chamada.
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.");
Eu peguei este exemplo no JavaScript Patterns Crie aplicativos melhores com padrões de codificação e design Pelo livro de Stoyan Stefanov , caso você precise de uma classe de implementação simples, como o objeto singltone, use a função imediata da seguinte maneira:
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
};
};
}());
E você pode verificar este exemplo seguindo o caso de teste:
//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
Essa abordagem passa em todos os casos de teste, enquanto a implementação estática privada falha quando a extensão do protótipo é usada (pode ser corrigida, mas não será simples), e a implementação estática pública menos aconselhável, porque a instância é exposta ao público.
Acho que encontrei a maneira mais limpa de programar em JavaScript, mas você precisará de imaginação. Eu recebi essa idéia de uma técnica de trabalho no livro "javascript the good parts".
Em vez de usar a nova palavra-chave, você pode criar uma classe como esta:
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;
}
Você pode instanciar o objeto acima dizendo:
var objInst = Class(); // !!! NO NEW KEYWORD
Agora, com este método de trabalho em mente, você pode criar um singleton como este:
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 };
}();
Agora você pode obter sua instância chamando
var obj = ClassSingleton.getInstance();
Eu acho que essa é a maneira mais legal, pois a "Classe" completa nem sequer é acessível.
O @CMS e o @zzzzBov deram respostas maravilhosas, mas apenas para adicionar minha própria interpretação, com base na minha mudança para o desenvolvimento node.js pesado do PHP / Zend Framework, onde os padrões singleton eram comuns.
O seguinte código documentado para comentários é baseado nos seguintes requisitos:
Meu código é muito semelhante ao do @ zzzzBov, exceto que eu adicionei uma cadeia de protótipos ao construtor e mais comentários que devem ajudar os que vêm do PHP ou de uma linguagem semelhante a traduzir a natureza prototípica do OOP tradicional para Javascripts. Pode não ser o "mais simples", mas acredito que seja o mais adequado.
// declare 'Singleton' as the returned value of a self-executing anonymous function
var Singleton = (function () {
"use strict";
// 'instance' and 'constructor' should not be availble 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'
Observe que tecnicamente, a função anônima de execução automática é, ela própria, um Singleton, conforme demonstrado com agrado no código fornecido pelo @CMS. O único problema aqui é que não é possível modificar a cadeia de protótipos do construtor quando o próprio construtor é anônimo.
Lembre-se de que, para Javascript, os conceitos de "público" e "privado" não se aplicam como em PHP ou Java. Mas alcançamos o mesmo efeito, aproveitando as regras de disponibilidade de escopo funcional do Javascript.
var a = Singleton.getInstance('foo'); var b = new a.constructor('bar');
Não sei por que ninguém trouxe isso à tona, mas você pode fazer:
var singleton = new (function() {
var bar = 123
this.foo = function() {
// whatever
}
})()
A resposta mais clara deve ser essa do livro Learning JavaScript Design Patterns de Addy Osmani.
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 = "Im 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;
}
};
})();
Acredito que esta é a maneira mais simples / limpa e mais intuitiva, embora exija ES7:
export default class Singleton { static instance; constructor(){ if(instance){ return instance; } this.state = "duke"; this.instance = this; } }
O código fonte é de: adam-bien.com
new Singleton()
posso colocar minhas 5 moedas? Eu tenho uma função construtora, ex.
var A = function(arg1){
this.arg1 = arg1
};
O que eu preciso fazer é que todos os objetos criados por esse CF sejam iguais.
var X = function(){
var instance = {};
return function(){ return instance; }
}();
teste
var x1 = new X();
var x2 = new X();
console.log(x1 === x2)
Eu achei o seguinte o padrão Singleton mais fácil, porque o uso do novo operador torna isso imediatamente disponível na função, eliminando a necessidade de retornar um literal de objeto:
var singleton = new (function () {
var private = "A private value";
this.printSomething = function() {
console.log(private);
}
})();
singleton.printSomething();
Aqui está o exemplo simples para explicar o padrão singleton em javascript.
var Singleton=(function(){
var instance;
var init=function(){
return {
display:function(){
alert("This is a Singleton patern demo");
}
};
};
return {
getInstance:function(){
if(!instance){
alert("Singleton check");
instance=init();
}
return instance;
}
};
})();
// In this call first display alert("Singleton check")
// and then alert("This is a Singleton patern demo");
// It means one object is created
var inst=Singleton.getInstance();
inst.display();
// In this call only display alert("This is a Singleton patern demo")
// it means second time new object is not created,
// it uses the already created object
var inst1=Singleton.getInstance();
inst1.display();
Eu precisava de vários singletons com:
e foi assim que eu inventei:
createSingleton ('a', 'add', [1, 2]);
console.log(a);
function createSingleton (name, construct, args) {
window[name] = {};
window[construct].apply(window[name], args);
window[construct] = null;
}
function add (a, b) {
this.a = a;
this.b = b;
this.sum = a + b;
}
args deve ser Array para que isso funcione; se você tiver variáveis vazias, basta passar []
Usei o objeto window na função, mas poderia ter passado um parâmetro para criar meu próprio escopo
Os parâmetros name e construct são apenas String para que window [] funcione, mas com algumas verificações simples, window.name e window.construct também são possíveis.
Que tal dessa maneira, apenas garantir que a classe não possa ser nova novamente.
Por isso, você pode usar o instanceof
op, também, você pode usar a cadeia de protótipos para herdar a classe, é uma classe regular, mas não pode ser nova, se você deseja obter a instância, basta usargetInstance
function CA()
{
if(CA.instance)
{
throw new Error('can not new this class');
}else{
CA.instance = this;
}
}
/**
* @protected
* @static
* @type {CA}
*/
CA.instance = null;
/** @static */
CA.getInstance = function()
{
return CA.instance;
}
CA.prototype =
/** @lends CA#*/
{
func: function(){console.log('the func');}
}
// initilize the instance
new CA();
// test here
var c = CA.getInstance()
c.func();
console.assert(c instanceof CA)
// this will failed
var b = new CA();
Se você não deseja expor o instance
membro, basta encerrá-lo.
A seguir, é apresentado o trecho do meu percurso para implementar um padrão singleton. Isso me ocorreu durante um processo de entrevista e achei que deveria capturar isso em algum lugar.
/*************************************************
* SINGLETON PATTERN IMPLEMENTATION *
*************************************************/
//since there are no classes in javascript, every object is technically a singleton
//if you don't inherit from it or copy from it.
var single = {};
//Singleton Implementations
//Declaring as a Global Object...you are being judged!
var Logger = function() {
//global_log is/will be defined in GLOBAL scope here
if(typeof global_log === 'undefined'){
global_log = this;
}
return global_log;
};
//the below 'fix' solves the GLOABL variable problem but
//the log_instance is publicly available and thus can be
//tampered with.
function Logger() {
if(typeof Logger.log_instance === 'undefined'){
Logger.log_instance = this;
}
return Logger.log_instance;
};
//the correct way to do it to give it a closure!
function logFactory() {
var log_instance; //private instance
var _initLog = function() { //private init method
log_instance = 'initialized';
console.log("logger initialized!")
}
return {
getLog : function(){ //the 'privileged' method
if(typeof log_instance === 'undefined'){
_initLog();
}
return log_instance;
}
};
}
/***** TEST CODE ************************************************
//using the Logger singleton
var logger = logFactory();//did i just gave LogFactory a closure?
//create an instance of the logger
var a = logger.getLog();
//do some work
//get another instance of the logger
var b = logger.getLog();
//check if the two logger instances are same?
console.log(a === b); //true
*******************************************************************/
o mesmo pode ser encontrado em minha essência página
function Unicode()
{
var i = 0, unicode = {}, zero_padding = "0000", max = 9999;
//Loop through code points
while (i < max) {
//Convert decimal to hex value, find the character, then pad zeroes to the codepoint
unicode[String.fromCharCode(parseInt(i, 16))] = ("u" + zero_padding + i).substr(-4);
i = i + 1;
}
//Replace this function with the resulting lookup table
Unicode = unicode;
}
//Usage
Unicode();
//Lookup
Unicode["%"]; //returns 0025
Você pode fazer isso com decoradores, como neste exemplo abaixo, para TypeScript:
class YourClass {
@Singleton static singleton() {}
}
function Singleton(target, name, descriptor) {
var instance;
descriptor.value = () => {
if(!instance) instance = new target;
return instance;
};
}
Então você usa seu singleton assim:
var myInstance = YourClass.singleton();
No momento da redação deste artigo, os decoradores não estão prontamente disponíveis nos mecanismos JavaScript. Você precisa garantir que o tempo de execução do JavaScript tenha os decoradores realmente ativados ou use compiladores como Babel e TypeScript.
Observe também que a instância singleton é criada "preguiçosa", ou seja, é criada somente quando você a utiliza pela primeira vez.
Padrão do módulo: no "estilo mais legível". Você pode ver facilmente quais métodos são públicos e quais são privados
var module = (function(_name){
/*Local Methods & Values*/
var _local = {
name : _name,
flags : {
init : false
}
}
function init(){
_local.flags.init = true;
}
function imaprivatemethod(){
alert("hi im a private method");
}
/*Public Methods & variables*/
var $r = {}; //this object will hold all public methods.
$r.methdo1 = function(){
console.log("method1 call it");
}
$r.method2 = function(){
imaprivatemethod(); //calling private method
}
$r.init = function(){
inti(); //making init public in case you want to init manually and not automatically
}
init(); //automatically calling init method
return $r; //returning all publics methods
})("module");
agora você pode usar métodos públicos como
module.method2 (); // -> Estou chamando um método privado por um alerta de método público ("oi, sou um método privado")
Singleton:
Garanta que uma classe tenha apenas uma instância e forneça um ponto de acesso global a ela.
O Padrão Singleton limita o número de instâncias de um objeto específico a apenas uma. Essa instância única é chamada de singleton.
O objeto Singleton é implementado como uma função anônima imediata. A função é executada imediatamente envolvendo-a entre colchetes, seguida por dois colchetes adicionais. É chamado anônimo porque não tem nome.
Programa de amostra,
var Singleton = (function () {
var instance;
function createInstance() {
var object = new Object("I am the instance");
return object;
}
return {
getInstance: function () {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
function run() {
var instance1 = Singleton.getInstance();
var instance2 = Singleton.getInstance();
alert("Same instance? " + (instance1 === instance2));
}
run()
Mais simples / mais limpo para mim significa também simplesmente entender e não há sinos e assobios, como são discutidos na versão Java da discussão:
O que é uma maneira eficiente de implementar um padrão singleton em Java?
A resposta que se encaixaria melhor / mais limpa do meu ponto de vista é:
https://stackoverflow.com/a/70824/1497139
E só pode ser traduzido parcialmente para JavaScript. Algumas das diferenças em Javascript são:
Mas, dada a sintaxe mais recente da ECMA, é possível se aproximar de:
Padrão Singleton como exemplo de classe JavaScript
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;
}
}
Exemplo de uso
console.log(Singleton.getInstance().field1);
console.log(Singleton.getInstance().field2);
Resultado de exemplo
DefaultField1
DefaultField2
function Once() {
return this.constructor.instance || (this.constructor.instance = this);
}
function Application(name) {
let app = Once.call(this);
app.name = name;
return app;
}
Se você estiver em aulas:
class Once {
constructor() {
return this.constructor.instance || (this.constructor.instance = this);
}
}
class Application extends Once {
constructor(name) {
super();
this.name = name;
}
}
Teste:
console.log(new Once() === new Once());
let app1 = new Application('Foobar');
let app2 = new Application('Barfoo');
console.log(app1 === app2);
console.log(app1.name); // Barfoo
Se você deseja usar classes:
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);
A saída para o acima será:
console.log(x.name,x.age,y.name,y.age) // s 1 s 1
Outra maneira de escrever Singleton usando a função
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);
A saída para o acima será:
console.log(a.name,a.age,b.name,b.age)// s 1 s 1