7

EDITAR: Al final lo descubrí por la respuesta de Bergi.Cómo crear un objeto con miembros privados usando Object.create() en lugar de nuevo

Gracias Bergi.

pubPrivExample = (function() { 
    return { 
     init : function() { 
      var private; 

      this.setPrivate = function (p) { 
       private = p; 
      }; 
      this.getPrivate = function() { 
       return private; 
      }; 
     }, 

     public : "This is public\n" 
    }; 
}()); 

var a; 

a = Object.create(pubPrivExample); 
a.init(); 
a.setPrivate("This is private"); 

document.write(a.getPrivate()); 

EDIT: Parece que las respuestas a mi pregunta están apagadas en una tangente. Realmente no estoy interesado en una fábrica y en realidad preferiría no utilizarla. Mi pregunta es sobre el estado privado. De las respuestas y comentarios de Bergi, creo que puedo hacer algo juntos.

Continuará ...

EDIT: Bergi ha comenzado a responder a la pregunta de abajo, pero dejó de lado la parte más importante - el estado privado.

He tenido tiempo para pensar en la idea más, pero sigo sin poder conseguir un estado privado usando Object.create() sin algún tipo de fábrica. Pero quiero estar equivocado, y Bergi aludió a una solución ... Siéntete libre de tomar la respuesta de Bergi como punto de partida.

ORIGINAL: Mi búsqueda para evitar new en Javascript me ha llevado a un lugar peculiar. Quiero miembros de objetos privados, pero no quiero renunciar a Object.create().

Aquí está el código.

var trackQueue = {}; 

trackQueue.factory = function() { 
    var that, queue; 
    that = this; 
    queue = []; 

    that.push = function (item) { 
     queue.push(item); 
    }; 

    that.work = function() { 
     document.write(queue + "<br />"); 
    }; 

    return { 
     work : that.work, 
     push : that.push 
    };   
}; 

var a = Object.create(trackQueue.factory()); 
a.push("a"); 
a.push("b"); 
a.push("c"); 

var b = Object.create(trackQueue.factory()); 
b.push("d"); 
b.push("e"); 
b.push("f"); 

a.work(); 
b.work(); 

Y un jsFiddle

http://jsfiddle.net/dsjbirch/Wj6cp/10/

Would init ser un nombre más idiomática/apropiado para el método factory?

¿Es esto una locura?

Sea amable - JavaScript no es mi lengua materna.

+2

¿Por qué no quieres usar 'new'? –

+1

Douglas crockford. – bluekeys

+2

Eso es desafortunado. –

Respuesta

2

Sí, un método init en el prototipo podría ser un nombre más apropiado:

var proto = { 
    init: function(args) { 
     // setting up private-scoped vars, 
     var example = args; 
     // privileged methods 
     this.accessPrivate = function(){ return example; }; 
     // and other stuff 
     this.public = 5; 
    }, 
    prop: "defaultvalue", 
    ... 
} 

var instance = Object.create(proto); 
instance.init(); 

Sin embargo, no hay absolutamente ninguna razón para no utilizar el constructor clásica con la nueva palabra clave, que combina con elegancia el Object.create y init llamada.

Y tenga en cuenta que está utilizando Object.create sin ningún tipo de uso. Su patrón de fábrica (aplicado perfectamente válido) devuelve buenos objetos. No es necesario crear nuevos objetos para cada uno que hereden de ellos. Sólo hacer:

var instance = trackQueue.factory(); 

Si te gusta el sonido del nombre del método "crear", podría utilizar un nombre más idiomática para su fábrica:

trackQueueFactory.create = function(args) {...}; 

EDIT: Tu idea de combinar el patrón de fábrica con herencia de prototipo no es tan incorrecto. Sin embargo, el objeto proto del cual todos los objetos fabricados heredan debe ser estático, en lugar de creando uno nuevo en cada invocación.Su código podría tener este aspecto:

var factory = { 
    proto: { 
     ... 
    }, 
    create: function(args) { 
     var product = Object.create(this.proto); 
     // set up private vars scoped to the create function 
     // privileged methods 
     product.doSomethingSpecial = function(){ ... }; 
     // and other stuff 
    } 
}; 

var a = factory.create(...); 
+0

¿Cómo configuro vars con ámbito privado en la función init en su ejemplo? – bluekeys

+0

De forma normal: use la palabra clave var o las declaraciones de funciones, y tendrán el alcance de la función init. – Bergi

2

Creo que esta es una forma clara de lograr sus requisitos:

var personFactory = function(id, name, age){ 
    var _id = id; 
    var _name = name; 
    var _age = age; 

    var personPrototype = { 
     getId: function(){ 
      return _id; 
     }, 
     setId: function(id){ 
      _id = id; 
     }, 
     getName: function(){ 
      return _name; 
     }, 
     setName: function(name){ 
      _name = name; 
     }, 
     getAge: function(){ 
      return _age; 
     }, 
     setAge: function(age){ 
      _age = age; 
     }, 
     work: function(){ 
      document.write(this.toString()); 
     }, 
     toString: function(){ 
      return "Id: " + _id + " - Name: " + _name + " - Age: " + _age; 
     } 
    }; 

    return Object.create(personPrototype); 
}; 

Uso:

var renato = personFactory(1, "Renato Gama", 25); 
console.log(renato.getName()); //logs "Renato Gama" 
renato.setName("Renato Mendonça da Gama"); 
console.log(renato.getName()); //logs "Renato Mendonça da Gama" 

Si no me equivoco esta es una los usos de MODULE PATTERN. Consulte this post para una mejor explicación. This es también una buena publicación sobre el tema.

+0

No, estás equivocado. Ha cometido el mismo error que el OP: no es necesario utilizar Object.create en objetos de ámbito privado. – Bergi

+0

No entiendo tu punto, ¿puedes aclarar un poco? No puedo ver por qué se considera un error. Incluso considero su segundo bloque de código similar al que escribí, que difiere en el hecho de que su prototipo es un miembro público de la fábrica. Estoy de acuerdo con su enfoque si su objeto de fábrica tendría más funciones públicas, pero crea(). – renatoargh

+0

¿Por qué no devuelve el objeto literal ("personPrototype") directamente? ¿De qué utilidad es Object.create en tu código? – Bergi

Cuestiones relacionadas