¿Por qué se desaconseja el uso de constructores al crear prototipos?

10

Antecedentes rápidos: en JavaScript, la función constructora para cada tipo de objeto tiene una prototypepropiedad. El se prototyperefiere a un objeto que cada objeto construido utiliza como el siguiente paso en su cadena de prototipo. Cuando desee que un tipo sea inherente a otro tipo, puede establecer el prototypetipo secundario en una nueva instancia del tipo primario.

Por ejemplo:

var Parent = function() { /* constructor business */ }
Parent.prototype.parentProp = "some parent property";

var Child = function() { /* constructor business */ }
Child.prototype = /*** !! Some prototype object goes here !! ***/

Mi pregunta se refiere a qué código debe ir en el " Some prototype object goes here" lugar en el código anterior. Mi primer instinto es construir una instancia del padre (es decir, new Parent()), pero en un comentario a una respuesta sobre ¿Es esta una forma segura de copiar un prototipo de objetos a otro? , un usuario escribe:

No, no lo use new bar()para el objeto prototipo.

(... que es una opinión que he visto en muchas respuestas y comentarios de SO, pero este es el único ejemplo que tengo en este momento).

La otra opción es usar Object.create(Parent.prototype)como Child.prototype. Hasta donde yo sé, esto también crea una nueva Parentinstancia, pero no ejecuta el Parentconstructor.

¿Alguien puede explicar por qué se debe evitar ejecutar la función de constructor al generar un objeto prototipo a partir de un tipo primario? ¿Hay algún problema técnico significativo que surja (quizás con múltiples niveles de herencia)? ¿O tal patrón es un mal uso de los constructores que choca con algunas mejores prácticas prototípicas (por ejemplo, ejecutar el constructor al crear un prototipo viola cierta separación de preocupaciones)?

apsillers
fuente

Respuestas:

5

Porque es una función que no necesita ser llamada. newno es tan diferente de una llamada a función normal en Javascript.

Un constructor puede hacer más que simplemente establecer campos. Por ejemplo, si valida los datos entrantes, causará un error de validación cuando simplemente intentaba establecer la cadena de herencia.

Y no necesitas Object.create, esto es suficiente:

function objectCreate( proto ) {
    function T(){}
    T.prototype = proto;
    return new T();
}
Esailija
fuente
Pero así es exactamente como Object.createse implementa.
Casey Chu
@CaseyChu en absoluto. Y lo mencioné porque en la publicación vinculada alguien dijo " Object.createno funciona en IE8", que es un comentario inútil cuando puede implementarlo para este caso de uso en 2 segundos en cualquier navegador.
Esailija
2

Ahora que mi comprensión se ha ampliado un poco, me gustaría aprovechar la respuesta de Esailija con un ejemplo específico:

Una preocupación específica es que un constructor puede establecer propiedades específicas de la instancia. Por lo tanto, si usa un objeto prototipo creado con new, todas sus instancias secundarias podrían compartir una sola propiedad específica de instancia definida por el constructor del prototipo.

Por ejemplo, supongamos que Parentcada instancia tiene una idpropiedad única establecida como tiempo de construcción:

var Parent = function() { this.id = Math.random(); }
Parent.prototype.parentProp = "some parent property";

var Child = function() { /* constructor business */ }
Child.prototype = new Parent();

Esto hará que todas las Child instancias compartan una única idpropiedad prototipo heredada del único new Parent()objeto utilizado como Child.prototype.

Un mejor enfoque para este caso es usar Object.createy llamar directamente al constructor padre (si es necesario) dentro del constructor hijo:

var Parent = function() { this.id = Math.random(); }
Parent.prototype.parentProp = "some parent property";

var Child = function() {
    // run `this` through the Parent constructor function
    Parent.apply(this, arguments);
}
Child.prototype = Object.create(Parent.prototype);
apsillers
fuente