TLDR; Não é necessário, mas provavelmente ajudará a longo prazo, e é mais preciso fazê-lo.
OBSERVAÇÃO: Muito editada como minha resposta anterior foi confusa e tinha alguns erros que eu perdi na pressa em responder. Obrigado a quem apontou alguns erros flagrantes.
Basicamente, é para ligar subclasses corretamente em Javascript. Quando subclasses, temos que fazer algumas coisas descoladas para garantir que a delegação prototípica funcione corretamente, incluindo a substituição de um prototype
objeto. A substituição de um prototype
objeto inclui oconstructor
, então precisamos corrigir a referência.
Vamos ver rapidamente como as 'classes' no ES5 funcionam.
Digamos que você tenha uma função construtora e seu protótipo:
//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',
}
Quando você chamar o construtor para instanciar, diga Adam
:
// instantiate using the 'new' keyword
var adam = new Person('Adam', 19);
A new
palavra-chave invocada com 'Person' basicamente executará o construtor Person com algumas linhas de código adicionais:
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
* }
*/
Se nós console.log(adam.species)
, a pesquisa falharmos na adam
instância, e procurar a cadeia de protótipos na sua .prototype
, que é Person.prototype
- e Person.prototype
tem uma .species
propriedade, para que a pesquisa seja bem-sucedida Person.prototype
. Em seguida, ele será registrado 'human'
.
Aqui, o Person.prototype.constructor
apontará corretamente para Person
.
Então agora a parte interessante, a chamada 'subclasse'. Se queremos criar uma Student
turma, que é uma subclasse da Person
turma com algumas alterações adicionais, precisamos garantir que os Student.prototype.constructor
pontos apontem para precisão do aluno.
Não faz isso por si só. Quando você subclasse, o código fica assim:
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: {}
Ligar new Student()
aqui retornaria um objeto com todas as propriedades que queremos. Aqui, se checarmos eve instanceof Person
, ele retornaria false
. Se tentarmos acessar eve.species
, ele retornará undefined
.
Em outras palavras, precisamos conectar a delegação para que eve instanceof Person
retorne true e para que instâncias de Student
delegar corretamente para Student.prototype
e depois Person.prototype
.
MAS, como a chamamos com a new
palavra - chave, lembre-se do que essa invocação adiciona? Isso chamaria Object.create(Student.prototype)
, e é assim que estabelecemos esse relacionamento delegacional entre Student
e Student.prototype
. Observe que, no momento, Student.prototype
está vazio. Portanto, procurar .species
uma instância de Student
falharia, pois delega apenas Student.prototype
, e a .species
propriedade não existe Student.prototype
.
Quando atribuímos Student.prototype
a Object.create(Person.prototype)
, Student.prototype
ele próprio delega e Person.prototype
, olhando para cima eve.species
, retornará human
como esperamos. Presumivelmente, gostaríamos que herdasse do Student.prototype AND Person.prototype. Então, precisamos consertar tudo isso.
/* 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);
Agora a delegação funciona, mas estamos substituindo Student.prototype
por um de Person.prototype
. Então, se ligarmos Student.prototype.constructor
, apontaria para em Person
vez de Student
. Este é por isso que precisamos corrigi-lo.
// 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
No ES5, nossa constructor
propriedade é uma referência que se refere a uma função que escrevemos com a intenção de ser um 'construtor'. Além do que a new
palavra - chave nos fornece, o construtor é uma função "simples".
No ES6, o constructor
agora está incorporado na maneira como escrevemos classes - como no, é fornecido como um método quando declaramos uma classe. Isso é simplesmente açúcar sintático, mas nos concede algumas conveniências, como o acesso a um super
quando estamos estendendo uma classe existente. Então, escreveríamos o código acima dessa maneira:
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;
}
}