reveal react patterns pattern patrón existe es6 diseño javascript singleton

react - javascript singleton pregunta



react singleton (10)

Acabo de leer algunos hilos en la discusión del diseño de singleton en javascript. Soy 100% nuevo en el diseño de patrones, pero como veo, ya que un Singleton por definición no tendrá la necesidad de crear una instancia, conceptualmente, si no se debe crear una instancia, en mi opinión no tiene que ser tratado como Objetos convencionales que se crean a partir de un plano (clases). Entonces, lo que me sorprende es por qué no solo pensar en un singleton simplemente como algo estáticamente disponible que está envuelto en algún tipo de alcance y que debería ser todo.

De los hilos que vi, la mayoría de ellos hacen un singleton a través de javascript tradicional

new function(){}

seguido de hacer un pseudo constructor.

Bueno, solo creo que un objeto literal es suficiente:

var singleton = { dothis: function(){}, dothat: function(){} }

¿Correcto? ¿O alguien tiene mejores ideas?

[actualización]: una vez más, lo que quiero decir es por qué la gente no usa una forma más sencilla de hacer singletons en javascript como lo mostraba en el segundo fragmento, si hay una razón absoluta, por favor dígamelo. Por lo general tengo miedo de este tipo de situaciones que simplifico mucho las cosas: D



El último cuadro de código muestra lo que he visto a los desarrolladores de JS llamar a su versión de diseño OO en Javascript.

Los singetones están destinados a ser objetos singulares que no pueden construirse (excepto, supongo, en la definición inicial. Usted tiene uno, instancia global de un singleton.


El patrón de singleton se implementa creando una clase con un método que crea una nueva instancia de la clase si no existe una. Si ya existe una instancia, simplemente devuelve una referencia a ese objeto. 1

(function (global) { var singleton; function Singleton () { // singleton does have a constructor that should only be used once this.foo = "bar"; delete Singleton; // disappear the constructor if you want } global.singleton = function () { return singleton || (singleton = new Singleton()); }; })(window); var s = singleton(); console.log(s.foo); var y = singleton(); y.foo = "foo"; console.log(s.foo);

No solo declara el singleton como un objeto porque eso lo instancia, no lo declara. Tampoco proporciona un mecanismo para el código que no conoce una referencia previa al singleton para recuperarlo. El singleton no es el objeto / clase que devuelve el singleton, es una estructura. Esto es similar a cómo las variables cerradas no son cierres, el alcance de la función que proporciona el cierre es el cierre.


El punto de usar el "pseudo constructor" es que crea un nuevo ámbito variable. Puede declarar variables locales dentro de la función que están disponibles dentro de cualquier función anidada pero no desde el ámbito global.

En realidad hay dos maneras de hacerlo. Puede llamar a la función con new como en su ejemplo, o simplemente llamar a la función directamente. Hay pequeñas diferencias en cómo escribiría el código, pero son esencialmente equivalentes.

Tu segundo ejemplo podría escribirse así:

var singleton = new function () { var privateVariable = 42; // This can be accessed by dothis and dothat this.dothis = function () { return privateVariable; }; this.dothat = function () {}; }; // Parentheses are allowed, but not necessary unless you are passing parameters

o

var singleton = (function () { var privateVariable = 42; // This can be accessed by dothis and dothat return { dothis: function () { return privateVariable; }, dothat: function () {} }; })(); // Parentheses are required here since we are calling the function

También puede pasar argumentos a cualquiera de las funciones (deberá agregar paréntesis al primer ejemplo).


Estoy de acuerdo contigo, la forma más sencilla es usar un objeto literal, pero si quieres miembros privados , puedes implementar aprovechando los closures :

var myInstance = (function() { var privateVar; function privateMethod () { // ... } return { // public interface publicMethod1: function () { // private members can be accessed here }, publicMethod2: function () { // ... } }; })();

Sobre la new function(){} construcción de la new function(){} , simplemente usará una función anónima como una constructor function , el contexto dentro de esa función será un nuevo objeto que será devuelto.

Edición: En respuesta al comentario de @ J5 , que es simple de hacer, en realidad creo que este puede ser un buen ejemplo para usar un patrón de definición de función perezosa :

function singleton() { var instance = (function() { var privateVar; function privateMethod () { // ... } return { // public interface publicMethod1: function () { // private members can be accessed here }, publicMethod2: function () { // ... } }; })(); singleton = function () { // re-define the function for subsequent calls return instance; }; return singleton(); // call the new function }

Cuando se llama a la función la primera vez, hago la instancia de objeto y reasigno singleton a una nueva función que tiene esa instancia de objeto en su cierre.

Antes del final de la primera llamada, ejecuto la función singleton redefinida que devolverá la instancia creada.

Las siguientes llamadas a la función singleton simplemente devolverán la instance que está almacenada en su cierre, porque la nueva función es la que se ejecutará.

Puedes probar que comparando el objeto devuelto:

singleton() == singleton(); // true

El operador == para objetos devolverá true solo si la referencia de objeto de ambos operandos es la misma, devolverá falso incluso si los objetos son idénticos pero son dos instancias diferentes:

({}) == ({}); // false new Object() == new Object(); // false


He usado la segunda versión ( var singleton = {}; ) para todo, desde las extensiones de Firefox hasta los sitios web, y funciona muy bien. Una buena idea es no definir las cosas dentro de los corchetes, pero fuera de ella con el nombre del objeto, así:

var singleton = {}; singleton.dothis = function(){ }; singleton.someVariable = 5;


La especificación ES5 nos permite usar Object.create ():

var SingletonClass = (function() { var instance; function SingletonClass() { if (instance == null) { instance = Object.create(SingletonClass.prototype); } return instance; } return { getInstance: function() { return new SingletonClass(); } }; })(); var x = SingletonClass.getInstance(); var y = SingletonClass.getInstance(); var z = new x.constructor();

Esto es bueno, ya que no tenemos que preocuparnos por las fugas de nuestro constructor, siempre terminamos con la misma instancia.

Esta estructura también tiene la ventaja de que nuestro Singleton no se construye solo hasta que se requiere. Además, usar el cierre como lo hacemos aquí evita que el código externo use nuestra variable de "instancia", accidental o de otra manera. Podemos crear más variables privadas en el mismo lugar y podemos definir cualquier cosa que nos importe exportar públicamente en nuestro prototipo de clase.


Qué tal esto:

function Singleton() { // --------------- // Singleton part. // --------------- var _className = null; var _globalScope = null; if ( !(this instanceof arguments.callee) ) { throw new Error("Constructor called as a function."); } if ( !(_className = arguments.callee.name) ) { throw new Error("Unable to determine class name.") } _globalScope = (function(){return this;}).call(null); if ( !_globalScope.singletons ) { _globalScope.singletons = []; } if ( _globalScope.singletons[_className] ) { return _globalScope.singletons[_className]; } else { _globalScope.singletons[_className] = this; } // ------------ // Normal part. // ------------ var _x = null; this.setx = function(val) { _x = val; }; // setx() this.getx = function() { return _x; }; // getx() function _init() { _x = 0; // Whatever initialisation here. } // _init() _init(); } // Singleton() var p = new Singleton; var q = new Singleton; p.setx(15); q.getx(); // returns 15


Robé esto de la respuesta de / CMS , y lo cambié para que pueda ser invocado como:

MySingleton.getInstance().publicMethod1();

Con la ligera alternancia:

var MySingleton = { // These two lines getInstance: function() { // These two lines var instance = (function() { var privateVar; function privateMethod () { // ... console.log( "b" ); } return { // public interface publicMethod1: function () { // private members can be accessed here console.log( "a" ); }, publicMethod2: function () { // ... privateMethod(); } }; })(); singleton = function () { // re-define the function for subsequent calls return instance; }; return singleton(); // call the new function } }


También me he preguntado acerca de esto, pero solo para mí es razonable definir un objeto con funciones. No tiene sentido crear un constructor al que nadie debe llamar, para crear un objeto sin prototipo, cuando solo puede definir el objeto directamente.

Por otro lado, si desea que su singleton sea una instancia de alguna "clase" existente, es decir, desea que tenga algún otro objeto como prototipo, entonces necesita usar una función constructora, de modo que puede establecer su propiedad prototype antes de llamarla.