este.constructor.prototipo – no puede sobrescribir completamente, ¿pero puede escribir accesorios individuales?

TL; DR? ¿Por qué no puedo sobrescribir el prototipo de un constructor desde el constructor?

Estoy averiguando mi patrón para la herencia prototípica. No me gusta cómo los prototipos generalmente se definen externamente desde un constructor, y quiero encapsular lógicamente las cosas mejor.

Descubrí que la única línea mágica que esperaba que funcionara, no funciona.

function Orifice(){ this.exhaust=function(){}; this.ingest=function(){}; } var standardOrifice = new Orifice(); function Sphincter(){ this.constructor.prototype = standardOrifice; // <-- does not work this.relax=function(){}; this.tighten=function(){}; } 

Curiosamente, puedo escribir propiedades individuales para este this.constructor.prototype , pero no puedo sobrescribir el objeto prototipo completo de la misma forma que se puede hacer fuera de la definición de un constructor.

Así que cosas como estas funcionan:

  this.constructor.prototype.exhaust = standardOrifice.exhaust; this.constructor.prototype.ingest = standardOrifice.ingest; 

Para lo cual puedo crear una función de clonación simple para manejar esto:

 function extend(target){ return { from: function(obj){ target.__proto__ = obj.constructor.prototype; for (key in obj) if (obj.hasOwnProperty(key)) target[key]=obj[key]; return target; } }; } 

Afortunadamente en mis pruebas hasta el momento, esta técnica parece funcionar bien, aunque no estoy seguro de si hay detalles o casos de rendimiento que podría estar perdiendo.

 function Sphincter(){ extend(this.constructor.prototype).from(standardOrifice); //... } 

¿Por qué no puedo sobrescribir el prototipo de un constructor desde el constructor? Sin embargo, ¿puedo hacerlo fuera del constructor? ¿Y las propiedades de escritura funcionan individualmente desde dentro de un constructor?

¿Por qué no puedo sobrescribir el prototipo de un constructor desde el constructor?

Puedes, pero es demasiado tarde. La nueva instancia ya ha sido generada, heredando del prototipo anterior. Quizás lea cómo funciona el new .

No me gusta cómo los prototipos generalmente se definen externamente desde un constructor.

Esa es la forma como es. Realmente no debería configurar el prototipo desde el constructor, sino que se ejecutaría cada vez que se creara una nueva instancia. Eso es específicamente lo que se supone que no son los prototipos. Consulte también Asignación de métodos prototipo * dentro de la función constructora: ¿por qué no?

y quiero encapsular lógicamente las cosas mejor.

Es posible que desee echar un vistazo a los diversos (reveladores) patrones de módulos . O tal vez incluso en algún marco de Class .

Actualmente estoy buscando razones más concretas por las que no debería avanzar con el patrón que he presentado.

No funciona en Internet Explorer. No funcionaría en ningún entorno compatible con ES5 que no admita la propiedad __proto__ . Nunca debes usarlo para establecer un prototipo en un objeto existente. En su lugar, use Object.create (o su shim) para corregir la herencia de JavaScript , lo que requiere que sobrescriba el prototipo fuera del constructor.

Mi sugerencia es llamar a su extend auxiliar fuera del constructor, que todavía tiene una buena syntax.

Respuesta a la pregunta específica

¿Por qué no puedo sobrescribir el prototipo de un constructor desde el constructor?

Es porque los constructores se llaman realmente después de que su objeto ya haya sido instanciado. Y dado que su objeto ha logrado crear instancias antes de que su constructor haya tocado algo, a su constructor también se le ha asignado un prototipo “predeterminado”.

Agregar propiedades a this.constructor.prototype parece funcionar, porque en realidad está manipulando el objeto prototipo predeterminado preasignado del constructor, del que heredan todas sus instancias.

En mis ejemplos, this.constructor.prototype prototipo de constructor terminó refiriéndose al prototipo asignado por defecto del constructor: por lo tanto, sobreescribirlo significaba que todas las instancias nuevas a partir de ese momento tendrían ese nuevo prototipo, como dijo Bergi, “demasiado tarde”, – su instancia actual no tendría ese nuevo prototipo, ya que todavía tiene el antiguo prototipo asignado por defecto porque ya se ha instanciado.

Un mejor patrón para evitar tonterías

He llegado a comprender que las técnicas presentadas en mi pregunta simplemente no funcionarán. La pregunta en sí misma generalmente es errónea. Al combinar la sabiduría de Bergi con mis propios sesgos personales, he llegado a este patrón como un medio para evitar tener que encontrar una respuesta a la pregunta original por completo:

 function extend(p){ return { to: function(C){ for (k in p) if (p.hasOwnProperty(k)) C.prototype[k]=p[k]; return C; } }; }; var orifice = new function Orifice(){ this.exhaust=function(){}; this.ingest=function(){}; }; var Sphincter = extend(orifice).to(function Sphincter(){ this.relax=function(){}; this.tighten=function(){}; }); 


Aquí está la función extender, expandida:

 function extend(parentObject){ return { to: function(ChildConstructor){ for (key in parentObject) if (parentObject.hasOwnProperty(key)) ChildConstructor.prototype[key] = parentObject[key]; return ChildConstructor; } }; }; 

Lo usé para probar que funciona:

 // TESTING var s=new Sphincter(); var tests=['relax','tighten','exhaust','ingest']; for (var i in tests) console.log("s."+tests[i]+"() is "+(tests[i]in s?"present :)":"MISSING!"));