¿Por qué es necesario configurar el constructor del prototipo?

Resuelto trinth asked hace 13 años • 15 respuestas

En la sección sobre herencia en el artículo de MDN Introducción a Javascript orientado a objetos , noté que configuraron el prototipo.constructor:

// correct the constructor pointer because it points to Person
Student.prototype.constructor = Student;  

¿Tiene esto algún propósito importante? ¿Está bien omitirlo?

trinth avatar Dec 10 '11 09:12 trinth
Aceptado

No siempre es necesario, pero tiene sus usos. Supongamos que queremos crear un método de copia en la Personclase base. Como esto:

// define the Person Class  
function Person(name) {
    this.name = name;
}  

Person.prototype.copy = function() {  
    // return new Person(this.name); // just as bad
    return new this.constructor(this.name);
};  

// define the Student class  
function Student(name) {  
    Person.call(this, name);
}  

// inherit Person  
Student.prototype = Object.create(Person.prototype);

Ahora bien, ¿qué pasa cuando creamos uno nuevo Studenty lo copiamos?

var student1 = new Student("trinth");  
console.log(student1.copy() instanceof Student); // => false

La copia no es una instancia de Student. Esto se debe a que (sin comprobaciones explícitas), no tendríamos forma de devolver una Studentcopia de la clase "base". Sólo podemos devolver un Person. Sin embargo, si hubiéramos reiniciado el constructor:

// correct the constructor pointer because it points to Person  
Student.prototype.constructor = Student;

...entonces todo funciona como se esperaba:

var student1 = new Student("trinth");  
console.log(student1.copy() instanceof Student); // => true
Wayne avatar Dec 10 '2011 03:12 Wayne

¿Tiene esto algún propósito importante?

Si y no.

En ES5 y versiones anteriores, JavaScript en sí no se usaba constructorpara nada. Definía que el objeto predeterminado en la prototypepropiedad de una función lo tendría y que se referiría a la función, y eso era todo . Nada más en la especificación se refería a ello.

Eso cambió en ES2015 (ES6), que comenzó a usarlo en relación con las jerarquías de herencia. Por ejemplo, Promise#thenutiliza la constructorpropiedad de la promesa a la que la invoca (a través de SpeciesConstructor ) al crear la nueva promesa para regresar. También participa en la subtipificación de matrices (a través de ArraySpeciesCreate ).

Fuera del lenguaje en sí, a veces la gente lo usaba cuando intentaba construir funciones genéricas de "clonación" o simplemente cuando querían referirse a lo que creían que sería la función constructora del objeto. Mi experiencia es que usarlo es raro, pero a veces la gente lo usa.

¿Está bien omitirlo?

Está ahí de forma predeterminada, solo necesitas volver a colocarlo cuando reemplazas elprototype objeto en la propiedad de una función :

Student.prototype = Object.create(Person.prototype);

Si no haces esto:

Student.prototype.constructor = Student;

... luego Student.prototype.constructorhereda del Person.prototypeque (presumiblemente) tiene constructor = Person. Entonces es engañoso. Y, por supuesto, si está subclasificando algo que lo usa (como Promiseo Array) y no usa class¹ (que maneja esto por usted), querrá asegurarse de configurarlo correctamente. Básicamente: es una buena idea.

Está bien si nada en su código (o el código de la biblioteca que usa) lo usa. Siempre me he asegurado de que estuviera correctamente conectado.

Por supuesto, con la classpalabra clave de ES2015 (también conocida como ES6), la mayoría de las veces la habríamos usado, ya no tenemos que hacerlo, porque la manejamos nosotros cuando lo hacemos.

class Student extends Person {
}

¹ "... si estás subclasificando algo que lo usa (como Promiseo Array) y no usa class..."  - Es posible hacer eso, pero es una verdadera molestia (y un poco tonto). Tienes que usar Reflect.construct.

T.J. Crowder avatar Feb 21 '2016 16:02 T.J. Crowder