web-dev-qa-db-fra.com

Essayer de comprendre la différence entre prototype et constructeur en JavaScript

Je suis nouveau sur JavaScript, pour comprendre ce concept, j'ai lu de nombreux articles concernant les prototypes et les constructeurs, mais où que j'aille, je suis confus.

La confusion survient lorsque les gens parlent simultanément de constructeur et de prototype.

Dans l'exemple suivant

var employee = function Emp(name) {
    this.name = name;
}
var jack = new employee("Jack Dwain");

employee.constructor //gives Function()

employee.prototype // gives  Emp {}

employee.prototype.constructor //gives Emp(name)

jack.constructor //gives Emp(name)

jack.prototype //gives undefined
  1. prototype est un moyen par lequel JS réalise l'héritage, puisque Emp(name) est la fonction de base, le prototype est référencé à la même fonction elle-même. C'est ce qui s'est passé?

  2. En quoi employee.constructor Et employee.prototype.constructor Diffèrent?

  3. Pourquoi est-ce que jack.prototype Est undefined c'est-à-dire s'il hérite de la fonction Emp(name) pourquoi il n'a pas référencé cette fonction?

  4. Comment puis-je me prédire clairement sans taper dans la console ce que le prototype ou le constructeur ou le prototype.constructor ...... rapporte

42
Ein2012

C'est une chose assez difficile à comprendre si vous avez l'habitude d'étendre des objets dans d'autres langages OOP, mais je ferai de mon mieux pour expliquer leur utilisation et ce qui est Je vais supposer que vous connaissez d’autres OOP langues. Corrigez-moi si je me trompe.

Toutes les fonctions ont le prototype Function (). Ils héritent de toutes les fonctionnalités de base de Function comme toString () et valueOf ().

Ensuite, il y a un constructeur. C'est ce que vous utilisez pour initialiser un objet avec.

p = new Foo();

Donc, dans ce cas, nous avons deux choses.

  • Un function Foo Avec Function comme prototype (Foo)
  • Un objet Function avec Foo() comme constructeur (p)

(me suit encore?)

Le constructeur Foo() peut remplacer certaines fonctionnalités de base du constructeur Function, mais aussi le laisser tel quel et en faire bon usage.

Si vous connaissez les principes de OOP, le prototype est la classe de base, le constructeur de votre classe actuelle. Dans OOP ce qui précède serait class Foo extends Function

Vous pouvez également commencer l'héritage avec cette configuration complète de prototype et de constructeur créant des objets plus complexes au fur et à mesure tout en partageant des fonctionnalités.

Par exemple ceci:

// make a object initialiser extending Function. in oop `class Foo extends Function`

function Foo(bar) {
    this.baz = bar;
}
Foo.prototype.append = function(what) {
    this.baz += " " + what;
};
Foo.prototype.get() {
    return this.baz
}

Disons maintenant que nous voulons différentes façons de sortir le baz de là. un pour la consignation de la console et un pour le mettre dans la barre de titre. Nous pourrions faire une grande chose au sujet de notre classe Foo, mais nous ne le faisons pas, parce que nous devons faire des choses complètement différentes avec les nouvelles classes mais sont faites pour différentes implémentations. La seule chose dont ils ont besoin pour partager sont l'objet baz et les setters et les getters.

Nous devons donc l'étendre pour utiliser un terme OOP. Dans OOp, ce serait le résultat final souhaité class Title extends Foo(){}. Voyons donc comment y arriver.

function Title(what) {
    this.message = what;
}

À ce stade, la fonction Titre ressemble à ceci:

  • fonction prototype
  • constructeur constructeur

Donc, pour l'étendre Foo, nous devons changer le prototype.

Title.prototype = new Foo();
  • prototype Foo
  • constructeur Foo

Cela se fait en initialisant un nouvel objet Foo () par rapport au prototype. Maintenant, c'est essentiellement un objet Foo appelé Title. Ce n'est pas ce que nous voulons car maintenant nous ne pouvons pas accéder à la partie message dans le titre. Nous pouvons faire étendre correctement Foo () en réinitialisant le constructeur sur Title

Title.prototype.constructor = Title;
  • prototype Foo
  • Titre du constructeur

Maintenant, nous sommes confrontés à un autre problème. Le constructeur de Foo n'est pas initialisé donc nous nous retrouvons avec un this.baz Non défini

Pour résoudre ce problème, nous devons appeler le parent. En Java vous le feriez avec super(vars), en php $parent->__construct($vars).

En javascript, nous devons modifier le constructeur de la classe Title pour appeler le constructeur de l'objet parent.

Ainsi, le constructeur de la classe Titre deviendrait

function Title(what) {
    Foo.call(this,what);
    this.message = what;
}

En utilisant la propriété d'objet Function Foo héritée, nous pouvons initialiser l'objet Foo dans l'objet Title.

Et maintenant, vous avez un objet hérité correctement.

Ainsi, au lieu d'utiliser un mot clé comme extend comme les autres OOP langues, il utilise prototype et constructor.

32
Tschallacka

employee.constructor // donne Function ()

En JavaScript, les fonctions sont également des objets, qui peuvent être construits en utilisant son propre constructeur qui est Function . Vous pouvez donc écrire le code suivant pour obtenir une instance de Function.

var employee2 = new Function('a', 'b', 'return a+b');

La même chose se produit lorsque vous créez une fonction en utilisant un littéral de fonction comme dans votre cas. Et la propriété constructeur de cet objet fait également référence au même objet/classe Function natif.

employee.prototype // donne Emp {}

Chaque objet en JavaScript est associé à un prototype. Bien que seul le prototype des objets fonction soit directement accessible avec le .prototype. Ce même prototype est copié sur son prototype d'objets lorsque vous créez des objets avec le mot clé new. Cette copie est principalement responsable de l'héritage/extension. Bien que le prototype soit copié, il n'est pas directement réparable comme dans le cas des objets Function. Il est disponible de manière non standard avec .__proto__. Le code suivant retournera vrai.

jack.__proto__==employee.prototype

employee.prototype.constructor // donne Emp (nom)

Comme indiqué dans la documentation de Object.prototype.constructor . Cela renvoie une référence à la fonction Object qui a créé le prototype de l'instance. Ici, l'objet référencé est employee.prototype et not employee. C'est un peu complexe mais le prototype de l'objet employee.prototype a été créé par la fonction Emp (nom)

jack.constructor // donne Emp (nom)

Comme indiqué au point précédent, ce prototype d'objets a été créé par la fonction Emp (nom) lorsque vous avez créé l'objet en utilisant new Emp (),

jack.prototype // donne undefined

jack n'est pas un objet de fonction, vous ne pouvez donc pas accéder à son prototype comme ça. Vous pouvez accéder (pas de manière standard) au prototype de jack comme suit.

jack.__proto__
8
Vishwanath

Si vous souhaitez créer un javascript objet vous pouvez simplement déclarer un nouvel objet et lui donner des propriétés (j'ai choisi de m'objectiver):

var myself= {
    name:"Niddro",
    age:32
};

Cette méthode vous permet de créer un objet. Si ce que vous voulez avoir est un prototype décrivant une personne en général, où vous pouvez déclarer plusieurs personnes avec la même configuration. Pour créer un prototype, vous pouvez utiliser un constructeur, cul vu ci-dessous:

//Constructor
function generalNameForObject(param1, param2,...) {
    //Give the object some properties...
}

J'ai un prototype (une recette) à l'esprit que je veux appeler personne et il devrait contenir le nom et l'âge des propriétés et j'utiliserai un constructeur pour le faire:

function person(name,age) {
    this.name=name;
    this.age=age;
}

La fonction de construction ci-dessus décrit le prototype de mes objets personne.

Créez une nouvelle personne en appelant la fonction de construction:

var myself = new person("Niddro",31);
var OP = new person("rajashekar thirumala",23);

Le temps passe et je me rends compte que j'ai un anniversaire donc je dois changer la propriété du prototype:

myself.age=32;

Si vous voulez ajouter des propriétés à la construction, vous devez l'ajouter manuellement dans la fonction de construction:

function person(name,age,rep) {
    this.name=name;
    this.age=age;
    this.reputation=rep;
}

Au lieu de cela, vous pouvez ajouter des propriétés au prototype en procédant comme suit (ici "prototype" est une commande réelle et pas seulement un nom):

function person(name,age,rep) {
    this.name=name;
    this.age=age;
}
person.prototype.reputation=105;

notez que cela ajoutera une réputation de 105 pour tous les objets créés.

J'espère que cela vous a permis de mieux comprendre la relation entre le constructeur et le prototype.

5
Niddro

Constructeur:

function Foo(x) {
    this.x =x;
}

Foo est le constructeur. Un constructeur est une fonction.

Il existe deux façons d'utiliser ce constructeur Foo.

"Les objets sont créés à l'aide de constructeurs dans de nouvelles expressions. Par exemple, new Date (2009,11) crée un nouvel objet Date. L'appel d'un constructeur sans utiliser new a des conséquences qui dépendent du constructeur. Par exemple, Date () produit une chaîne représentation de la date et de l'heure actuelles plutôt que d'un objet. "

Source ECMA-262

Cela signifie que si Foo renvoie quelque chose (via return "somevalue";) Alors typeof Foo() est le type de la valeur de retour.

D'un autre côté, lorsque vous appelez

var o = new Foo();

JavaScript fait juste

var o = new Object();
o.[[Prototype]] = Foo.prototype;
Foo.call(o);

Prototype:

Lorsque vous appelez o.a, Javascript vérifie d'abord si a est une propriété propre de l'objet o. Sinon, javascript recherchera la chaîne de propriétés pour trouver a.

Pour plus d'informations sur la chaîne de propriétés, consultez mdn .

La propriété prototype du constructeur a une fonctionnalité vraiment puissante, qui n'est pas disponible dans les classes. S'il est utile, c'est un autre débat. La propriété prototype du constructeur peut modifier les propriétés de chaque instance liée à ce prototype dans leur chaîne de prototypes.

Résumé:

Remarque: Ce n'est pas une définition exacte, le but du résumé est juste de vous donner une idée des contrôleurs et des prototypes.

Si vous utilisez un constructeur avec le mot clé new, les constructeurs et les prototypes ont un objectif similaire, même s'ils sont complètement différents. Un constructeur initialise les propriétés de l'objet, il fournit donc des propriétés. Un prototype fournit également des propriétés via la chaîne de propriétés (héritage basé sur un prototype).

3
user8175891

Pourtant, la vérité est que cette approche peut être erronée dans de nombreuses situations. En Javascript, lorsque vous liez une méthode au mot-clé this, vous fournissez cette méthode uniquement à cette instance particulière et elle n'a pas vraiment de relation avec une instance d'objet de ce constructeur, à peu près comme une méthode statique. En gardant à l'esprit que les fonctions sont des citoyens de première classe en Javascript, nous pouvons les traiter comme des objets, dans ce cas, nous ajoutons uniquement une propriété à une instance d'un objet fonction. Ce n'est qu'une partie de l'histoire, vous devez également savoir que toute méthode attachée via ceci sera re-déclarée pour chaque nouvelle instance que nous créons, ce qui pourrait affecter négativement l'utilisation de la mémoire de l'application si nous souhaitons créer autant d'instances.

0
abdulwahhab