Pourquoi est-il nécessaire de définir le constructeur du prototype?

294

Dans la section sur l'héritage dans l'article MDN Introduction to Object Oriented Javascript , j'ai remarqué qu'ils définissaient le prototype.constructor:

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

Cela sert-il un objectif important? Peut-on l'omettre?

trinth
la source
23
Heureux que vous ayez posé cette question: j'ai lu la même documentation hier et j'étais curieux de savoir le raisonnement derrière la définition explicite du constructeur également.
Wylie
6
Je viens de le signaler, cette question est maintenant liée dans l'article que vous avez lié!
Marie
7
rien est nécessaire
nothingisnecessary
1
Le subclass.prototype.constructorpointera vers parent_classsi vous n'écrivez pas subclass.prototype.constructor = subclass; Autrement dit, l'utilisation subclass.prototype.constructor()directe produira un résultat inattendu.
KuanYu Chu

Réponses:

263

Ce n'est pas toujours nécessaire, mais il a ses utilisations. Supposons que nous voulions faire une méthode de copie sur la Personclasse de base . Comme ça:

// 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);

Maintenant, que se passe-t-il lorsque nous créons un nouveau Studentet le copions?

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

La copie n'est pas une instance de Student. En effet (sans contrôles explicites), nous n'aurions aucun moyen de renvoyer une Studentcopie de la classe "base". Nous ne pouvons renvoyer qu'un Person. Cependant, si nous avions réinitialisé le constructeur:

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

... alors tout fonctionne comme prévu:

var student1 = new Student("trinth");  
console.log(student1.copy() instanceof Student); // => true
Wayne
la source
34
Remarque: L' constructorattribut n'a pas de signification particulière dans JS, vous pouvez donc aussi bien l'appeler bananashake. La seule différence est que le moteur initialise automatiquement constructorsur f.prototypechaque fois que vous déclarez une fonction f. Cependant, il peut être remplacé à tout moment.
user123444555621
58
@ Pumbaa80 - j'obtenir votre point, mais le fait que le moteur automatiquement initialise constructorsignifie qu'il n'ont une signification particulière dans JS, à peu près par définition.
Wayne
13
Je veux juste préciser que la raison pour laquelle le comportement que vous avez dit fonctionne est que vous utilisez à la return new this.constructor(this.name);place de return new Person(this.name);. Puisque this.constructorc'est la Studentfonction (parce que vous la définissez avec Student.prototype.constructor = Student;), la copyfonction finit par appeler la Studentfonction. Je ne sais pas quelle était votre intention avec ce //just as badcommentaire.
CEGRD
12
@lwburk qu'entendez-vous par "// tout aussi mauvais"?
CEGRD
6
Je pense que je comprends. Mais, si le Studentconstructeur avait ajouté un argument supplémentaire comme Student(name, id):? Devons-nous alors remplacer la copyfonction, appeler la Personversion de l'intérieur, puis copier également la idpropriété supplémentaire ?
snapfractalpop
76

Cela sert-il un objectif important?

Oui et non.

Dans ES5 et versions antérieures, JavaScript lui-même n'utilisait constructorrien. Il a défini que l'objet par défaut sur la prototypepropriété d' une fonction l' aurait et qu'il ferait référence à la fonction, et c'était tout . Rien d'autre dans la spécification n'y fait référence du tout.

Cela a changé dans ES2015 (ES6), qui a commencé à l'utiliser en relation avec les hiérarchies d'héritage. Par exemple, Promise#thenutilise la constructorpropriété de la promesse à laquelle vous l'appelez (via SpeciesConstructor ) lors de la construction de la nouvelle promesse de retour. Il est également impliqué dans les tableaux de sous-typage (via ArraySpeciesCreate ).

En dehors du langage lui-même, les gens l'utilisaient parfois lorsqu'ils essayaient de créer des fonctions génériques de «clone» ou tout simplement lorsqu'ils voulaient se référer à ce qu'ils pensaient être la fonction constructeur de l'objet. D'après mon expérience, son utilisation est rare, mais parfois les gens l'utilisent.

Peut-on l'omettre?

Il est là par défaut, il vous suffit de le remettre lorsque vous remplacez l'objet sur la prototypepropriété d' une fonction :

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

Si vous ne le faites pas:

Student.prototype.constructor = Student;

... Student.prototype.constructorhérite alors de Person.prototypece qui (vraisemblablement) a constructor = Person. C'est donc trompeur. Et bien sûr, si vous sous-classifiez quelque chose qui l'utilise (comme Promiseou Array) et que vous n'utilisez pas class¹ (qui gère cela pour vous), vous voudrez vous assurer de le définir correctement. Donc en gros: c'est une bonne idée.

Ce n'est pas grave si rien dans votre code (ou le code de bibliothèque que vous utilisez) ne l'utilise. J'ai toujours veillé à ce qu'il soit correctement câblé.

Bien sûr, avec le classmot clé de ES2015 (aka ES6) , la plupart du temps nous l'aurions utilisé, nous n'avons plus à le faire, car il est géré pour nous lorsque nous le faisons

class Student extends Person {
}

¹ "... si vous sous-classifiez quelque chose qui l'utilise (comme Promiseou Array) et que vous n'utilisez pas class..."  - C'est possible de le faire, mais c'est vraiment une douleur (et un peu idiot). Vous devez utiliser Reflect.construct.

TJ Crowder
la source
12

TLDR; Pas super nécessaire, mais aidera probablement à long terme, et il est plus précis de le faire.

REMARQUE: Beaucoup de choses ont été modifiées car ma réponse précédente a été écrite de manière confuse et contient des erreurs que j'ai manquées dans ma précipitation à répondre. Merci à ceux qui ont signalé des erreurs flagrantes.

Fondamentalement, il s'agit de câbler correctement le sous-classement en Javascript. Lorsque nous sous-classons, nous devons faire des choses amusantes pour nous assurer que la délégation prototypique fonctionne correctement, notamment en écrasant un prototypeobjet. Le remplacement d'un prototypeobjet inclut le constructor, nous devons donc corriger la référence.

Voyons rapidement comment fonctionnent les «classes» dans ES5.

Disons que vous avez une fonction constructeur et son prototype:

//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',
}

Lorsque vous appelez le constructeur pour instancier, dites Adam:

// instantiate using the 'new' keyword
var adam = new Person('Adam', 19);

Le newmot-clé invoqué avec 'Person' exécutera le constructeur Person avec quelques lignes de code supplémentaires:

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 nous console.log(adam.species), la recherche échouera à l' adaminstance et recherchera la chaîne prototypique vers la sienne .prototype, qui est Person.prototype- et Person.prototype possède une .speciespropriété, la recherche réussira donc Person.prototype. Il se connectera ensuite 'human'.

Ici, le Person.prototype.constructorpointera correctement Person.

Alors maintenant, la partie intéressante, le soi-disant «sous-classement». Si nous voulons créer une Studentclasse, c'est-à-dire une sous-classe de la Personclasse avec quelques modifications supplémentaires, nous devons nous assurer que les Student.prototype.constructorpoints pointent vers Student pour plus de précision.

Il ne le fait pas tout seul. Lorsque vous sous-classe, le code ressemble à ceci:

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: {}

Appeler new Student()ici retournerait un objet avec toutes les propriétés que nous voulons. Ici, si nous vérifions eve instanceof Person, cela reviendrait false. Si nous essayons d'accéder eve.species, il reviendrait undefined.

En d'autres termes, nous devons câbler la délégation afin que eve instanceof Personrenvoie true et que les instances de Studentdélégué soient correctement envoyées à Student.prototype, puis Person.prototype.

MAIS puisque nous l'appelons avec le newmot - clé, rappelez-vous ce que cette invocation ajoute? Cela s'appellerait Object.create(Student.prototype), c'est ainsi que nous établissons cette relation de délégation entre Studentet Student.prototype. Notez qu'en ce moment, Student.prototypeest vide. Ainsi, la recherche d' .speciesune instance de Studentéchouerait car elle délègue uniquement Student.prototype et la .speciespropriété n'existe pas Student.prototype.

Lorsque nous nous attribuons Student.prototypeà Object.create(Person.prototype), Student.prototypelui - même , les délégués sont Person.prototyperenvoyés et la recherche eve.speciesrevient humancomme prévu. Vraisemblablement, nous voudrions qu'il hérite de Student.prototype ET Person.prototype. Nous devons donc régler tout cela.

/* 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);

Maintenant, la délégation fonctionne, mais nous remplaçons Student.prototypepar un de Person.prototype. Donc, si nous appelons Student.prototype.constructor, cela indiquerait au Personlieu de Student. C'est pourquoi nous devons y remédier.

// 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

Dans ES5, notre constructorpropriété est une référence qui fait référence à une fonction que nous avons écrite avec l'intention d'être un «constructeur». Mis à part ce que le newmot - clé nous donne, le constructeur est par ailleurs une fonction «simple».

Dans ES6, le constructorest désormais intégré dans la façon dont nous écrivons les classes - comme dans, il est fourni comme méthode lorsque nous déclarons une classe. Il s'agit simplement de sucre syntaxique, mais il nous offre certaines commodités comme l'accès à un superlorsque nous étendons une classe existante. Nous écririons donc le code ci-dessus comme ceci:

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;
   }
}
bthehuman
la source
eve instanceof Studentretourné true. Voir stackoverflow.com/questions/35537995/… pour des explications. Aussi quand vous dites à which is, at the moment, nothingquoi faites-vous référence? Chaque fonction a un prototype donc si je vérifie Student.prototypec'est quelque chose.
Aseem Bansal
Mon erreur. Il aurait dû lire «eve instanceof Person» qui retournerait faux. Je vais modifier cette partie. Vous avez raison de dire que chaque fonction possède une propriété prototype. Cependant , sans affecter le prototype à Object.create(Person.prototype), le Student.prototypeest vide. Donc, si nous nous connectons eve.species, il ne déléguera pas correctement jusqu'à sa superclasse, Personne, et il ne se connectera pas 'human'. Vraisemblablement, nous voulons que chaque sous-classe hérite de son prototype et aussi du prototype de son super.
bthehuman
Pour clarifier, which is, at the moment, nothingje voulais dire que l' Student.prototypeobjet est vide.
bthehuman
En savoir plus sur le prototype: Sans l'attribution de Student.prototypeà Object.create(Person.prototype)- qui est, si vous vous souvenez, de la même manière que toutes les instances de Person sont configurées pour déléguer à Person.prototype- la recherche d'une propriété sur une instance de Studentserait déléguée uniquement Student.prototype . Alors eve.speciessa recherche échouera. Si nous l'attribuons, Student.prototypelui - même se délègue alors Person.prototype, et la recherche eve.speciesrevient human.
bthehuman
Il semble qu'il y ait pas mal de choses ici: "C'est nécessaire lorsque vous essayez d'émuler la" sous-classe "[...] afin que lorsque vous vérifiez si une instance est instancele constructeur de la" sous-classe ", elle soit exacte." Non, instanceofn'utilise pas constructor. "Cependant, si nous recherchons le .prototype.constructor de l'étudiant, il pointerait toujours vers la personne" Non, ce sera Student. Je ne comprends pas l'intérêt de cet exemple. L'appel d'une fonction dans un constructeur n'est pas un héritage. "Dans ES6, le constructeur est maintenant une fonction réelle au lieu d'une référence à une fonction" Euh quoi?
Felix Kling
10

Je ne suis pas d'accord. Il n'est pas nécessaire de définir le prototype. Prenez exactement le même code mais supprimez la ligne prototype.constructor. Est-ce que quelque chose change? Maintenant, apportez les modifications suivantes:

Person = function () {
    this.favoriteColor = 'black';
}

Student = function () {
    Person.call(this);
    this.favoriteColor = 'blue';
}

et à la fin du code de test ...

alert(student1.favoriteColor);

La couleur sera bleue.

Un changement dans le prototype.constructor, d'après mon expérience, ne fait pas grand-chose sauf si vous faites des choses très spécifiques et très compliquées qui ne sont probablement pas de bonnes pratiques de toute façon :)

Edit: Après avoir fouillé un peu sur le Web et avoir fait quelques expérimentations, il semble que les gens définissent le constructeur de sorte qu'il «ressemble» à la chose en cours de construction avec «nouveau». Je suppose que je dirais que le problème avec cela est que javascript est un langage prototype - il n'y a pas d'héritage. Mais la plupart des programmeurs viennent d'un contexte de programmation qui fait de l'héritage «le chemin». Nous proposons donc toutes sortes de choses pour essayer de faire de ce langage prototypique un langage «classique», comme l'extension des «classes». Vraiment, dans l'exemple qu'ils ont donné, un nouvel élève est une personne - ce n'est pas une «extension» à partir d'un autre élève. Prolongez l'étudiant, et tout ce que vous '

Crockford est un peu fou et trop zélé, mais faites une lecture sérieuse sur certaines des choses qu'il a écrites .. cela vous fera regarder les choses très différemment.

Stephen
la source
8
Cela n'hérite pas de la chaîne prototype.
Cypher
1
@Cypher slow clap bienvenue dans la conversation, quatre ans plus tard. Oui, la chaîne de prototype est héritée, que vous remplaciez ou non le prototype.constructor. Essayez de le tester.
Stephen
7
Vous manquez le code qui hérite du prototype. Bienvenue sur Internet.
Cypher
1
L'extrait de code @Cypher était basé sur le code de l'article lié. Bienvenue à lire la question dans son intégralité. Oh. Attendre.
Stephen
1
@macher, je le voulais comme héritage classique. Mauvais choix de formulation de ma part.
Stephen
9

Cela a l'énorme écueil que si vous avez écrit

Student.prototype.constructor = Student;

mais alors s'il y avait un enseignant dont le prototype était aussi personne et vous avez écrit

Teacher.prototype.constructor = Teacher;

alors le constructeur étudiant est maintenant professeur!

Edit: Vous pouvez éviter cela en vous assurant que vous avez défini les prototypes Student et Teacher à l'aide de nouvelles instances de la classe Person créées à l'aide d'Object.create, comme dans l'exemple Mozilla.

Student.prototype = Object.create(Person.prototype);
Teacher.prototype = Object.create(Person.prototype);
James D
la source
1
Student.prototype = Object.create(...)est supposé dans cette question. Cette réponse n'ajoute rien d'autre qu'une confusion possible.
André Chalella
3
@ AndréNeves J'ai trouvé cette réponse utile. Object.create(...)est utilisé dans l'article MDN qui a engendré la question, mais pas dans la question elle-même. Je suis sûr que beaucoup de gens ne cliquent pas.
Alex Ross
L'article lié référencé dans la question utilise déjà Object.create (). Cette réponse et la modification de la réponse ne sont pas vraiment pertinentes, et c'est pour le moins déroutant :-)
Drenai
1
Le point le plus large est qu'il existe des pièges qui accrocheront les nouveaux utilisateurs aux prototypes Javascript. Si nous discutons en 2016, alors vous devriez vraiment utiliser les classes ES6, Babel et / ou Typescript. Mais si vous voulez vraiment construire manuellement des classes de cette façon, cela aide à comprendre comment les chaînes de prototypes fonctionnent vraiment pour tirer parti de leur puissance. Vous pouvez utiliser n'importe quel objet comme prototype et peut-être ne voulez-vous pas créer un nouvel objet distinct. De plus, avant que HTML 5 ne soit entièrement répandu, Object.create n'était pas toujours disponible, il était donc plus facile de configurer une classe de manière incorrecte.
James D
5

Jusqu'à présent, la confusion est toujours là.

En suivant l'exemple d'origine, comme vous avez un objet existant en student1tant que:

var student1 = new Student("Janet", "Applied Physics");

Supposons que vous ne vouliez pas savoir comment student1est créé, vous voulez juste un autre objet comme celui-ci, vous pouvez utiliser la propriété constructeur de student1like:

var student2 = new student1.constructor("Mark", "Object-Oriented JavaScript");

Ici, il ne sera pas possible d'obtenir les propriétés Studentsi la propriété constructeur n'est pas définie. Il créera plutôt un Personobjet.

Mahavir
la source
2

Vous avez un bel exemple de code expliquant pourquoi il est vraiment nécessaire de définir le constructeur du prototype.

function CarFactory(name){ 
   this.name=name;  
} 
CarFactory.prototype.CreateNewCar = function(){ 
    return new this.constructor("New Car "+ this.name); 
} 
CarFactory.prototype.toString=function(){ 
    return 'Car Factory ' + this.name;
} 

AudiFactory.prototype = new CarFactory();      // Here's where the inheritance occurs 
AudiFactory.prototype.constructor=AudiFactory;       // Otherwise instances of Audi would have a constructor of Car 

function AudiFactory(name){ 
    this.name=name;
} 

AudiFactory.prototype.toString=function(){ 
    return 'Audi Factory ' + this.name;
} 

var myAudiFactory = new AudiFactory('');
  alert('Hay your new ' + myAudiFactory + ' is ready.. Start Producing new audi cars !!! ');            

var newCar =  myAudiFactory.CreateNewCar(); // calls a method inherited from CarFactory 
alert(newCar); 

/*
Without resetting prototype constructor back to instance, new cars will not come from New Audi factory, Instead it will come from car factory ( base class )..   Dont we want our new car from Audi factory ???? 
*/
user3877965
la source
Votre createNewCarméthode consiste à créer des usines!? Cela semble également avoir dû être utilisé var audiFactory = new CarFactory("Audi")plutôt que d'utiliser l'héritage.
Bergi
Votre exemple utilise en this.constructorinterne, il n'est donc pas surprenant qu'il doive être défini. Avez-vous un exemple sans cela?
Dmitri Zaitsev
1

Plus besoin de «classes» de fonction sucrées ou d'utiliser «Nouveau» de nos jours. Utilisez des littéraux d'objet.

Le prototype Object est déjà une «classe». Lorsque vous définissez un objet littéral, il s'agit déjà d'une instance de l'objet prototype. Ceux-ci peuvent également agir comme prototype d'un autre objet, etc.

const Person = {
  name: '[Person.name]',
  greeting: function() {
    console.log( `My name is ${ this.name || '[Name not assigned]' }` );
  }
};
// Person.greeting = function() {...} // or define outside the obj if you must

// Object.create version
const john = Object.create( Person );
john.name = 'John';
console.log( john.name ); // John
john.greeting(); // My name is John 
// Define new greeting method
john.greeting = function() {
    console.log( `Hi, my name is ${ this.name }` )
};
john.greeting(); // Hi, my name is John

// Object.assign version
const jane = Object.assign( Person, { name: 'Jane' } );
console.log( jane.name ); // Jane
// Original greeting
jane.greeting(); // My name is Jane 

// Original Person obj is unaffected
console.log( Person.name ); // [Person.name]
console.log( Person.greeting() ); // My name is [Person.name]

Cela vaut la peine d'être lu :

Les langages orientés objet basés sur les classes, tels que Java et C ++, sont fondés sur le concept de deux entités distinctes: les classes et les instances.

...

Un langage basé sur un prototype, tel que JavaScript, ne fait pas cette distinction: il a simplement des objets. Un langage basé sur un prototype a la notion d'un objet prototypique, un objet utilisé comme modèle à partir duquel obtenir les propriétés initiales d'un nouvel objet. Tout objet peut spécifier ses propres propriétés, soit lors de sa création, soit lors de l'exécution. De plus, tout objet peut être associé comme prototype pour un autre objet, permettant au deuxième objet de partager les propriétés du premier objet

ucsarge
la source
1

Il est nécessaire lorsque vous avez besoin d'une alternative à toStringsans monkeypatching:

//Local
foo = [];
foo.toUpperCase = String(foo).toUpperCase;
foo.push("a");
foo.toUpperCase();

//Global
foo = [];
window.toUpperCase = function (obj) {return String(obj).toUpperCase();}
foo.push("a");
toUpperCase(foo);

//Prototype
foo = [];
Array.prototype.toUpperCase = String.prototype.toUpperCase;
foo.push("a");
foo.toUpperCase();

//toString alternative via Prototype constructor
foo = [];
Array.prototype.constructor = String.prototype.toUpperCase;
foo.push("a,b");
foo.constructor();

//toString override
var foo = [];
foo.push("a");
var bar = String(foo);
foo.toString = function() { return bar.toUpperCase(); }
foo.toString();

//Object prototype as a function
Math.prototype = function(char){return Math.prototype[char]};
Math.prototype.constructor = function() 
  {
  var i = 0, unicode = {}, zero_padding = "0000", max = 9999;
  
  while (i < max) 
    {
    Math.prototype[String.fromCharCode(parseInt(i, 16))] = ("u" + zero_padding + i).substr(-4);

    i = i + 1;
    }    
  }

Math.prototype.constructor();
console.log(Math.prototype("a") );
console.log(Math.prototype["a"] );
console.log(Math.prototype("a") === Math.prototype["a"]);

Paul Sweatte
la source
Qu'est-ce que tout cela est censé faire? foo.constructor()??
Ry-
0

EDIT, j'avais en fait tort. Commenter la sortie ne change pas du tout son comportement. (Je l'ai testé)


Oui il faut. Quand tu fais

Student.prototype = new Person();  

Student.prototype.constructordevient Person. Par conséquent, l'appel Student()retournerait un objet créé par Person. Si vous le faites

Student.prototype.constructor = Student; 

Student.prototype.constructorest réinitialisé Student. Désormais, lorsque vous l'appelez, Student()il s'exécute Student, ce qui appelle le constructeur parent Parent(), il renvoie l'objet correctement hérité. Si vous n'avez pas réinitialisé Student.prototype.constructoravant de l'appeler, vous obtiendrez un objet qui n'aurait aucune des propriétés définies Student().

bob invisible
la source
3
La construction du prototype peut devenir une personne, mais cela est approprié car elle hérite de toutes les propriétés et méthodes de la personne. La création d'un nouvel étudiant () sans définir le prototype.constructor appelle correctement son propre constructeur.
Stephen
0

Étant donné la fonction de constructeur simple:

function Person(){
    this.name = 'test';
}


console.log(Person.prototype.constructor) // function Person(){...}

Person.prototype = { //constructor in this case is Object
    sayName: function(){
        return this.name;
    }
}

var person = new Person();
console.log(person instanceof Person); //true
console.log(person.sayName()); //test
console.log(Person.prototype.constructor) // function Object(){...}

Par défaut (à partir de la spécification https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor ), tous les prototypes obtiennent automatiquement une propriété appelée constructeur qui renvoie à la fonction sur dont c'est une propriété. Selon le constructeur, d'autres propriétés et méthodes peuvent être ajoutées au prototype, ce qui n'est pas une pratique très courante, mais elle est toujours autorisée pour les extensions.

Donc, répondez simplement: nous devons nous assurer que la valeur dans prototype.constructor est correctement définie comme elle est supposée par la spécification.

Faut-il toujours régler correctement cette valeur? Il aide au débogage et rend la structure interne cohérente par rapport aux spécifications. Nous devrions certainement quand notre API est utilisée par des tiers, mais pas vraiment quand le code est finalement exécuté dans le runtime.

kospiotr
la source
0

Voici un exemple de MDN que j'ai trouvé très utile pour comprendre ses utilisations.

En JavaScript, nous avons async functionsqui renvoie l' objet AsyncFunction . AsyncFunctionn'est pas un objet global mais on peut le récupérer en utilisant la constructorpropriété et l'utiliser.

function resolveAfter2Seconds(x) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(x);
    }, 2000);
  });
}

// AsyncFunction constructor
var AsyncFunction = Object.getPrototypeOf(async function(){}).constructor

var a = new AsyncFunction('a', 
                          'b', 
                          'return await resolveAfter2Seconds(a) + await resolveAfter2Seconds(b);');

a(10, 20).then(v => {
  console.log(v); // prints 30 after 4 seconds
});
Hitesh Kumar
la source
-1

Ce n'est pas nécessaire. C'est juste l'une des nombreuses choses traditionnelles que font les champions de la POO pour essayer de transformer l'héritage prototypique de JavaScript en héritage classique. La seule chose que ce qui suit

Student.prototype.constructor = Student; 

fait, c'est que vous avez maintenant une référence du "constructeur" actuel.

Dans la réponse de Wayne, qui a été marquée comme correcte, vous pourriez exactement la même chose que le code suivant

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

avec le code ci-dessous (remplacez simplement this.constructor par Person)

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

Dieu merci, avec ES6, les puristes de l'héritage classique peuvent utiliser les opérateurs natifs du langage comme classe, étend et super et nous n'avons pas à voir comme les corrections prototype.constructor et les références parentales.

Roumelis George
la source