TLDR; No es súper necesario, pero probablemente ayudará a largo plazo, y es más preciso hacerlo.
NOTA: Mucho editado ya que mi respuesta anterior fue escrita de manera confusa y tenía algunos errores que no tuve en mi prisa por responder. Gracias a quienes señalaron algunos errores atroces.
Básicamente, es conectar subclases correctamente en Javascript. Cuando subclasemos, tenemos que hacer algunas cosas extrañas para asegurarnos de que la delegación prototípica funcione correctamente, incluida la sobrescritura de un prototype
objeto. Sobrescribir un prototype
objeto incluye el constructor
, por lo que debemos corregir la referencia.
Veamos rápidamente cómo funcionan las 'clases' en ES5.
Digamos que tiene una función de constructor y su prototipo:
//Constructor Function
var Person = function(name, age) {
this.name = name;
this.age = age;
}
//Prototype Object - shared between all instances of Person
Person.prototype = {
species: 'human',
}
Cuando llame al constructor para crear una instancia, diga Adam
:
// instantiate using the 'new' keyword
var adam = new Person('Adam', 19);
La new
palabra clave invocada con 'Persona' básicamente ejecutará el constructor Persona con algunas líneas de código adicionales:
function Person (name, age) {
// This additional line is automatically added by the keyword 'new'
// it sets up the relationship between the instance and the prototype object
// So that the instance will delegate to the Prototype object
this = Object.create(Person.prototype);
this.name = name;
this.age = age;
return this;
}
/* So 'adam' will be an object that looks like this:
* {
* name: 'Adam',
* age: 19
* }
*/
Si nosotros console.log(adam.species)
, la búsqueda fallará en la adam
instancia, y buscamos la cadena prototípica en ella .prototype
, que esPerson.prototype
- y Person.prototype
tiene una .species
propiedad, por lo que la búsqueda tendrá éxito Person.prototype
. Luego se registrará 'human'
.
Aquí, el Person.prototype.constructor
apuntará correctamente Person
.
Así que ahora la parte interesante, la llamada 'subclase'. Si queremos crear una Student
clase, que es una subclase de la Person
clase con algunos cambios adicionales, tendremos que asegurarnos de que Student.prototype.constructor
apunta a Student para mayor precisión.
No hace esto por sí mismo. Cuando subclases, el código se ve así:
var Student = function(name, age, school) {
// Calls the 'super' class, as every student is an instance of a Person
Person.call(this, name, age);
// This is what makes the Student instances different
this.school = school
}
var eve = new Student('Eve', 20, 'UCSF');
console.log(Student.prototype); // this will be an empty object: {}
Llamar new Student()
aquí devolvería un objeto con todas las propiedades que queremos. Aquí, si lo comprobamos eve instanceof Person
, volveríafalse
. Si intentamos acceder eve.species
, volvería undefined
.
En otras palabras, necesitamos conectar la delegación para que eve instanceof Person
devuelva verdadero y para que las instancias de Student
delegar correctamenteStudent.prototype
, y luego Person.prototype
.
PERO ya que lo estamos llamando con la new
palabra clave, ¿recuerda lo que agrega esa invocación? Llamaría Object.create(Student.prototype)
, que es cómo establecemos esa relación de delegación entre Student
y Student.prototype
. Tenga en cuenta que en este momento, Student.prototype
está vacío. Por lo tanto, buscar .species
una instancia de Student
fallará ya que solo delega Student.prototype
, y el.species
propiedad no existe en Student.prototype
.
Cuando asignamos Student.prototype
a sí mismo Object.create(Person.prototype)
, Student.prototype
luego delegamos a Person.prototype
, y mirar hacia arriba eve.species
regresará human
como esperamos. Presumiblemente nos gustaría que herede de Student.prototype AND Person.prototype. Entonces necesitamos arreglar todo eso.
/* This sets up the prototypal delegation correctly
*so that if a lookup fails on Student.prototype, it would delegate to Person's .prototype
*This also allows us to add more things to Student.prototype
*that Person.prototype may not have
*So now a failed lookup on an instance of Student
*will first look at Student.prototype,
*and failing that, go to Person.prototype (and failing /that/, where do we think it'll go?)
*/
Student.prototype = Object.create(Person.prototype);
Ahora la delegación funciona, pero estamos sobrescribiendo Student.prototype
con una de Person.prototype
. Entonces, si llamamos Student.prototype.constructor
, apuntaría a en Person
lugar de Student
. Es por eso que necesitamos arreglarlo.
// Now we fix what the .constructor property is pointing to
Student.prototype.constructor = Student
// If we check instanceof here
console.log(eve instanceof Person) // true
En ES5, nuestra constructor
propiedad es una referencia que se refiere a una función que hemos escrito con la intención de ser un 'constructor'. Aparte de lo que new
nos da la palabra clave, el constructor es una función 'simple'.
En ES6, constructor
ahora está integrado en la forma en que escribimos clases, como en, se proporciona como un método cuando declaramos una clase. Esto es simplemente azúcar sintáctico, pero nos otorga algunas comodidades como el acceso a super
cuando estamos ampliando una clase existente. Entonces escribiríamos el código anterior de esta manera:
class Person {
// constructor function here
constructor(name, age) {
this.name = name;
this.age = age;
}
// static getter instead of a static property
static get species() {
return 'human';
}
}
class Student extends Person {
constructor(name, age, school) {
// calling the superclass constructor
super(name, age);
this.school = school;
}
}