2011-05-05 5 views
6

Escenario 1 - todo funciona:Patrón necesario: crear un nuevo objeto que devuelve una función ejecutable y se hereda de un prototipo

var AwesomeObject = function() 
{ 
    var self = this; 
    self.whatstuff = 'really awesome'; 
} 

AwesomeObject.prototype.doStuff = function() 
{ 
    var self = this; 
    console.log('i did '+self.whatstuff+' stuff'); 
    return self; 
} 

var awesome = new AwesomeObject(); //returns a new AwesomeObject 
awesome.doStuff(); // prints 'i did really awesome stuff' on the console 

Ahora quiero que sea aún awesomer:

var AwesomeObject = function() 
{ 
    var f = function() { console.log('i am awesome'); } 
    var self = f; 
    self.whatstuff = 'really awesome'; 
    return self; 
} 

AwesomeObject.prototype.doStuff = function() 
{ 
    var self = this; 
    console.log('i did '+self.whatstuff+' stuff'); 
    return self; 
} 

var awesome = new AwesomeObject(); //returns the interal f object 
awesome(); // prints 'i am awesome' 
awesome.doStuff(); // throws an error 

nueva AwesomeObject debe devolver una función ejecutable en sí misma, por lo que puedo decir 'awesome();'

pero también quiero que herede el AwesomeObject.prototype.

sumando self.prototype = AwesomeObject.prototype; no ayuda.

var AwesomeObject = function() 
{ 
    var f = function() { console.log('i am awesome'); } 
    var self = f; 
    self.whatstuff = 'really awesome'; 
    self.prototype = AwesomeObject.prototype; 
    return self; 
} 

bien puedo copiar los AwesomeObject.prototype funciones - una tras otra - en el ámbito de f

var AwesomeObject = function() 
{ 
    var f = function() { console.log('i am awesome'); } 
    var self = f; 
    self.whatstuff = 'really awesome'; 
    self.doStuff = function() { AwesomeObject.prototype.doStuff.apply(self,arguments); } 
    return self; 
} 

pero yo creo que debe haber una mejor manera, un mejor patrón, ¿qué es?

este problema me vuelve loco, la ayuda sería muy apreciada.

en general: cómo crear un objeto función que

  • se pueden crear con el nuevo
  • devuelve un objeto de función que se puede ejecutar
  • hereda todas las propiedades y métodos de un prototipo dada

?

¿hay alguna manera?

THX Franz

+0

Creo que copie las funciones que necesita del prototipo. No debería necesitar usar apply(); simplemente haz self.doStuff = prototype.doStuff – Joel

Respuesta

8

Un patrón muy simple es una fábrica.

var AwesomeObject = (function() { 
    var AwesomeObject = function() { 
     this.whatstuff = 'really awesome'; 
    }; 

    AwesomeObject.prototype.doStuff = function() { 
     console.log('i did ' + this.whatstuff + ' stuff'); 
     return this; 
    }; 

    return function() { 
     var o = new AwesomeObject(); 
     var f = function() { console.log("I am awesome"); }; 
     for (var k in o) { 
      f[k] = o[k];  
     } 

     return f; 
    }; 

})(); 

var foo = AwesomeObject(); 
foo(); 
foo.doStuff(); 

Live Example.

La idea es que separes tu función y tu objeto en dos cosas. Su objeto existe en el ámbito local de su función y la función puede usar el objeto.

El objeto en sí hereda completamente a través del prototipo.

La clave es reenviar todas las propiedades/métodos del objeto a la función.

Esta es la solución más limpia.

+0

las otras respuestas también fueron correctas. este parece ser el patrón más limpio (y funciona como se prometió). muchas gracias. –

+1

Observe que esta solución * no * devuelve un objeto que hereda de su prototipo personalizado, pero que devuelve un objeto 'Función' en el que se mezclan algunas propiedades. – Bergi

1

creo que no hay una buena manera de hacer esto. Rediseñaría tu programa para evitarlo.

Sin embargo, aquí hay una mala solución , dependiente de la plataforma (funciona en V8 utilizando no estándar __proto__ propiedad):

var PrototypeToBeInherited = {'inheritedProperty': 'inheritedPropertyValue'}; 

f = function() { 
    return "result"; 
}; 
f.__proto__ = PrototypeToBeInherited; 

f() 
=> "result"; 
f.inheritedProperty 
=> "inheritedPropertyValue" 

Para su requisito de que debe ser creado con la "nueva" , solo envuélvalo en la función:

F = function() { 
    return f; 
} 
var instance = new F(); 
+0

Voy a decir que '.__ proto__' debe evitarse debido a la dependencia de la plataforma y cambiar el prototipo interno de un objeto conduce dinámicamente al código de pesadilla. – Raynos

+0

thx mucho, ayudó a deshacerse del nudo que tenía en mis pensamientos –

2

Cuando se resuelve una propiedad, la cadena del prototipo se atraviesa como probablemente sepa. Pero si tiene un objeto awesome y trata de evaluar awesome.doStuff, entonces awesome.prototype nunca serán consultados por la propiedad. Puede verificar esto en su ejemplo, "doStuff" in awesome => false pero "doStuff" in awesome.prototype => true.

Entonces, lo que está haciendo no está cambiando las propiedades implícitas de awesome, está cambiando su prototipo, lo que significa que cualquier objeto creado haciendo new awesome tendrá esa propiedad. Verificación: "doStuff" in new awesome() => true.Y esto tiene sentido, ya que no hay forma de distinguir entre un constructor o una función normal al usar f/awesome.

El procedimiento en la resolución de una propiedad en un objeto po es más o menos como sigue:

  • Compruebe si p se define en o
  • Compruebe si p se define en o.__proto__ (uso de __proto__ es no- estándar pero ampliamente implementado, a excepción de jscript la última vez que lo comprobé y que ahora se ha desaprobado en SpiderMonkey)
  • Compruebe si p es de multado en o.constructor.prototype
  • Compruebe si p se define en o.constructor.prototype.prototype
  • etc

Así que una solución sería simplemente establecer o.__proto__ = AwesomeClass.prototype. Piense en __proto__ como un objeto intermediario oculto entre un objeto y su prototipo. Cada instancia recibe su propio objeto único __proto__. Pero esto está en desuso y no es estándar como dije.

También podríamos establecer los valores en Function.prototype, pero eso anularía otras propiedades de la función y afectaría a todas las instancias de la función. No queremos eso.

¿Qué queda? No mucho resulta. No hay forma de establecer el prototipo completo de un objeto mientras conserva su prototipo heredado. Tendrá que recorrer el prototipo y copiar todas las propiedades. Afortunadamente, esto permitirá que instanceof se comporte como se espera al trabajar con cadenas de constructores, así como también que permita la herencia/anulación de propiedades correctamente.

El problema es que no hay una forma integrada de copiar las propiedades de un objeto en otra, y que no hay una forma estándar de cambiar la cadena prototipo de un objeto ad-hoc (__proto__).

Utilice __proto__, o repita el prototipo.

+0

thx para el discurso en __proto__. ahora sé sobre proto, y ahora intentaré no usar __proto__ –

Cuestiones relacionadas