1. Use variables globales para guardar casos individuales
Esta es la forma más fácil de implementarlo
function persona () {this.createTime = new Date (); } var instancia = nueva persona (); función getInStance () {instancia de retorno; }Al cargar este JS, se crea y se guarda un objeto de persona a la variable global de instancia. Este objeto se toma cada vez que se usa. Si no lo ha usado una vez, se desperdicia el objeto que creó, podemos optimizarlo.
VAR Función de instancia getInstance () {if (! instancia) {instancia = nueva persona (); } instancia de retorno; }De esta manera, el objeto se crea solo cuando se usa por primera vez.
La desventaja de este método es que la instancia es una variable global. Cuando varias personas cooperan o el ciclo de desarrollo es relativamente largo, es difícil asegurarse de que la instancia no sea modificada ni sobrescribida por otros códigos. Es muy probable que cuando se llama la llamada, se encuentra que la instancia no es un objeto de persona en absoluto.
Consideremos el uso de cierres para encapsular para que ya no sea una variable global para resolver este problema.
2. Objeto de creación de cierre
var getInStance () {Var instancia; function de return () {if (! instancia) {instancia = nueva persona (); } instancia de retorno; }} ();De esta manera, la instancia está encapsulada y no hay necesidad de preocuparse por ser modificado.
Ahora puede obtener un singleton a través de la función getInstance (). Nueva pregunta, si creo un objeto a través de una nueva persona (), todavía obtengo múltiples objetos, y JavaScript no puede privatizar el constructor como Java. Entonces, ¿cómo podemos hacer que los objetos que son nuevos varias veces sean una instancia?
3. Instancia de caché de atributo estático del constructor
Mira el código primero
function persona () {// Si la instancia ha sido almacenada en caché, devolverá directamente la instancia en caché if (typeof persona.instance === 'object') {return persona.instance; } this.createTime = new Date (); // Persona de instancia en caché.instance = this; devolver esto; }Desde el código, podemos ver que la primera vez nueva, la condición de IF Devuelve falso, disminuirá, inicializará el objeto y luego guardará el objeto a la persona de propiedad estática.
La segunda vez nueva, la condición de IF Devuelve verdadera, devuelve directamente Person.Instance y el código inicializado no se reducirá. Entonces, no importa cuántas veces sea nueva, el objeto devuelto es el primer objeto creado.
Las desventajas de este método son las mismas que las del método uno. Persona. La entrada también es una propiedad pública y puede modificarse.
Consulemos el método 2. Uso de un cierre para encapsular puede resolver el problema
4. Reescribe el constructor
Este método debe usar cierres, pero no puede ser tan simple como el método dos. Necesitamos anular el constructor.
function persona () {// Cached instancia var instancia = this; this.createTime = new Date (); // Reescribe el constructor persona = function () {return instance; }}La primera vez que se llama nueva, el constructor original se almacena en caché primero y luego se inicializa, y el constructor se anula. Cuando sea nuevo en el futuro, el constructor original nunca se llamará, y el constructor de reescritura solo puede llamarse, y esta función siempre devuelve la instancia en caché.
El método anterior parece estar bien, pero a través de la siguiente prueba, puede encontrar el problema
// agregar atributo persona.prototype.prop1 = true; var p1 = nueva persona (); // Después de crear el objeto de inicialización, agregar atributo persona.prototype.prop2 = true; var p2 = nueva persona (); // Iniciar prueba console.log (p1.prop1); // El resultado es verdadero console.log (p2.prop1); // El resultado es verdadero console.log (p1.prop2); // El resultado no define console.log (p2.prop2); // El resultado es consolador sin defecto (p2.prop2); // El resultado el resultado no se define es incofinado que no se define es incefinido de inderfined es incefinido de inderfinado es incofinado es incefinido de inderfined es incefinido. console.log (p1.constructor === persona); // El resultado es falso console.log (p2.constructor === persona); // El resultado es falso
Los resultados esperados deberían ser ciertos.
Analice el código de prueba anterior
Persona.prototype.prop1 = true; Agrega el atributo PROP1 bajo el prototipo del constructor original y asigna un valor.
Después de ejecutar var p1 = new Person ();, el constructor de la persona ha sido reescrito
Por lo tanto, persona.prototype.prop2 = true; Agrega la propiedad Prop2 bajo el nuevo prototipo.
var p2 = nueva persona (); P2 y P1 son en realidad el mismo objeto, es decir, el objeto creado por el constructor original
Entonces P1 y P2 tienen la propiedad PROP1, pero no hay propiedad PROP2
Del mismo modo, el constructor de P1 y P2 también apunta al constructor original, y la persona ya no es la función original en este momento.
Para ejecutarse como se esperaba, se pueden lograr algunas modificaciones
function persona () {// Cached instancia var instancia = this; // Reescribir constructor persona = function () {return instance; } // Reserve la persona de atributo prototipo.prototype = this; // instancia = nueva persona (); // Restablecer la instancia de referencia del constructor.Constructor = Person; // Otra institucional de inicialización.CreateTime = new Date (); instancia de retorno; }Ejecute el código de prueba anterior y el resultado es cierto.
5. Carga perezosa:
En proyectos grandes o complejos, juega un papel de optimización: los componentes que son caros pero rara vez utilizados pueden envueltos en singleton de carga perezosa, programas de ejemplo:
/ * Singleton con miembros privados, paso 3. */Mynamespace.singleton = (function () {// privado miembros. Var privateatTribute1 = false; var privateTtribute2 = [1, 2, 3]; function privateMethod1 () {...} functemethod2 (args) {...} return {// miembros de los miembros públicos. Publicattribute: verdadero, verdadero, verdadero, 10, 10, 10, 10, args) {...} publicMethod1: function () {...}, publicMethod2: function (args) {...}};}) ();/ * esqueleto general para un singleton de carga perezoso, paso 1. */mynamespace.singleton = (function () {functive constructor () {// Todo del código de singleton normal va aquí. // privado. privateTribute2 = [1, 2, 3]; Lazy Loading Singleton, Paso 2. */mynamespace.singleton = (function () {function constructor () {// Todo el código de singleton normal va aquí ... ...} return {getInstance: function () {// El código de control va aquí.}}}}) ();/ *General Skeleton para un singlete de carga de carga perezoso, paso 3. * (function () {var UniqueInstance; // private atributo que contiene la instancia única. Function Constructor () {// Todo el código Singleton normal va aquí. ...} return {getInStance: function () {if (! Uniqueinstance) {// Instantiate solo si la instancia no existe. UniqueInstance = constructor ();} return UniqueinStance;}}}}) () () () ();6. Use Branch Singleton:
El código para un entorno específico se puede envolver en un singleton ramificado, programa de muestra:
/ * SimplexHrFactory Singleton, Paso 1. */Var simplexhrfactory = (function () {// Las tres ramas. Var Standard = {createExhRObject: function () {return new XMLHTTPREQUEST ();}}}; var ActiveXNew = {CreatexHRObject: function () {return New ActiveXObject ('' msxmlllhttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttT }}; Xmlhttprequest (); rama, intente cada método; ActiveXold.CreatexhRObject ();