Pour comprendre le prototype dans JS, vous devez d'abord comprendre les concepts suivants
1. Tout en js est un objet
2. Tout dans JS est dérivé de l'objet, c'est-à-dire que le point final de la chaîne prototype de toutes choses pointe vers l'objet.Protype
// ["Constructeur", "toString", "Tolocalestring", "ValueOf", "Hasownproperty", "isprototypeOf", // "PropertyIsEnumerable", "__definegetter__", "__lookupgetter__", "__defineSetter__", // "__lookupsetter__"] console.log (object.getownpropertyNames (object.prototype));
3. La relation subtile entre les constructeurs et les instances (objets) en js
Les constructeurs définissent les prototypes pour convenir des spécifications de leurs instances, puis construisent des instances à travers de nouvelles. Leur fonction est de produire des objets.
Le constructeur (méthode) lui-même est une instance de la méthode (fonction), donc il peut également être trouvé pour son __proto __ (Protochain)
Objet / fonction f () {} C'est le constructeur, l'un est fourni par l'API native JS, et l'autre est personnalisé
Nouveau objet () / new f () est une instance
Les exemples ne peuvent être visualisés que "uniquement" pour savoir sur quel prototype il est fabriqué sur la base.
Le prototype qui ne peut pas "redéfinit l'instance puis se trompe pour créer une instance de l'instance.
Pratiquez pour produire de véritables connaissances, et ce n'est qu'en observant / pensant vous-même que vous pouvez vraiment comprendre:
// Regardons d'abord ce que le constructeur est // fonction vide () {} fonction vide () {} console.log (function.prototype, fonction .__ proto__); // objet {} fonction vide () {} console.log (objet.prototype, objet .__ proto__); fonction f () {} // f {} fonction vide () {} console.log (f.prototype, f .__ proto__);Vous pouvez être étourdi, décomposons-le.
prototype
Le format de la sortie du prototype est: Nom du constructeur Prototype
Tout d'abord, jetons un coup d'œil à quel objet.prototype sorties?
Objet {} -> L'objet précédent est le nom du constructeur, et le suivant représente le prototype. Voici un {}, c'est-à-dire une instance d'un objet d'objet (objet vide)
Alors f {} Nous comprenons ce que cela signifie. F est le nom du constructeur, et le prototype est également un objet vide
// Jetons un coup d'œil à l'exemple construit par le constructeur var o = nouveau objet (); // var o = {}; // objet non défini {} console.log (o.prototype, o .__ proto__); fonction f () {} var i = new f (); // non défini f {} console.log (i.prototype, i .__ proto__);Allons un peu plus loin et définissons le prototype de F pour voir ce qui se passera?
fonction f () {} f.prototype.a = fonction () {}; var i = new f (); // non défini f {a: function} console.log (i.prototype, i .__ proto__);De cette façon, nous pouvons clairement voir que je suis construit à partir de f, le prototype est {a: function}, ce qui signifie qu'une méthode a a été ajoutée au prototype d'objet vide d'origine.
Changeons la situation, que se passera-t-il si le prototype qui couvre complètement F?
fonction f () {} f.prototype = {a: function () {}}; var i = new f (); // objet non défini {a: function} console.log (i.prototype, i .__ proto__);Hey ~ Pourquoi cela indique-t-il ici que je suis construit à partir d'objet? Non!
Parce que nous écrasons complètement le prototype de F, en fait, nous spécifions le prototype en tant qu'objet {a: function}, mais cela entraînera la perte des informations du constructeur d'origine et deviendra le constructeur spécifié par l'objet {a: function}.
Alors, quel est le constructeur de l'objet {a: function}?
Parce que l'objet {a: function} est en fait relatif à
var o = {a: function () {}} // nouvel objetAlors le constructeur d'O est bien sûr un objet
Corrons cette erreur
Fonction f () {} f.prototype = {a: function () {}} // Re-spécifier le constructeur correct f.prototype.constructor = f; var i = new f (); // non défini f {a: fonction, constructeur: fonction} console.log (i.prototype, i .__ proto__);Vous pouvez maintenant obtenir à nouveau les informations correctes du prototype ~
Chaîne prototype
Voyons alors ce qu'est la chaîne prototype?
En termes simples, c'est la même chose que la relation d'héritage (chaîne) dans la POO. Recherchez la couche par calque jusqu'à l'objet final. ProTotype
La chose la plus importante est de comprendre ce que sont les objets (instances). C'est simple, tout dans JS est des objets!
Ensuite, nous devons comprendre que tout objet a un prototype!
Alors prouvons-le:
Objet // Ceci est une fonction, la fonction est un objet d'instance de fonction, donc c'est l'objet .__ proto__ == function.prototype // Ensuite, le prototype de l'objet, true // il s'agit d'un objet ordinaire, donc l'instance de l'objet appartient à la fonction.prototype .__ Proto__ == Object.prototype // Vrai // Ceci est déjà le niveau supérieur de la chaîne prototype, donc le point final est Null // Ceci est déjà le niveau supérieur de la chaîne prototype, donc le point final est Null // Object.prototype .__ proto__ == null // true function // c'est aussi une fonction, oui! Fonction .__ proto__ == function.prototype // true function a () {} // c'est une fonction personnalisée, et c'est toujours une fonction après tout, c'est vrai! A .__ proto__ == function.prototype // Toute fonction est une instance de fonction, donc le prototype de A? var a = new a () a .__ proto__ == a.prototype // L'instance a est construite par le constructeur A, donc un prototype de a est défini par l'attribut prototype de A.Prototype .__ Proto__ == Object.prototype // Exemple d'objets ordinaires sont des objetsPrototype et __proto__
Chaque objet contient un __proto__ pointant vers le "prototype" de l'objet.
Une chose similaire est que chaque fonction contient un prototype. À quoi sert ce prototype d'objet?
Regardons le code suivant, en utilisant le constructeur pour créer un objet (ce qui précède est de créer un objet sous la forme d'une forme littérale).
fonction foo () {}; var foo = new foo (); console.log (foo .__ proto__);Imaginez-vous, à quoi indiquera-t-il le __proto__ de cet objet FOO?
Un objet contenant l'attribut constructeur? Peu importe si vous ne le comprenez pas beaucoup. Imprimez l'attribut prototype de la fonction foo et comparez-le à vous pour savoir.
fonction foo () {}; var foo = new foo (); console.log (foo .__ proto __); console.log (foo.prototype); console.log (foo .__ proto === foo.prototype);Il s'avère que le __proto__ de l'objet Foo qui sort de nouveau ne pointe que le prototype de la fonction foo.
foo .__ proto__ -> foo.prototype
Quel est l'intérêt de concevoir JS comme celui-ci? Rappelant ce qui a été mentionné ci-dessus, dans le monde de JS, les objets ne sont pas créés en fonction des classes (moules), mais sont dérivés de prototypes (un autre objet).
Lorsque nous effectuons de nouvelles opérations pour créer un nouvel objet, nous n'irons pas profondément dans la mise en œuvre spécifique de nouvelles opérations, mais nous sommes sûrs d'une chose - c'est-à-dire que nous indiquons un objet prototype pour le nouvel objet __proto__.
Juste ce code
fonction foo () {}; var foo = new foo ();Qui est Foo .__ Proto__ pointant? Pourquoi ne pouvez-vous pas indiquer la fonction foo elle-même? Bien que la fonction soit également un objet, j'en parlerai en détail si vous en avez l'occasion. Mais il n'est certainement pas approprié de pointer de foo .__ Proto__foo, car Foo est une fonction avec beaucoup de code logique. En tant qu'objet, il n'a aucun sens à hériter du traitement logique. Ce qu'il veut hériter, c'est l'attribut de "l'objet Prototype".
Par conséquent, chaque fonction générera automatiquement un objet prototype, et le __proto__ de l'objet nouveau de cette fonction pointe vers le prototype de cette fonction.
foo .__ proto__ -> foo.prototype
Résumer
Après avoir dit tellement de choses, je ne l'ai toujours pas expliqué complètement, il vaut donc mieux être sur l'image précédente. J'ai fait référence à des photos d'autres internautes, mais je sens toujours que je n'ai pas expliqué clairement, alors j'ai moi-même dessiné une photo. Si je pense que le mien est bon, veuillez l'aimer! (J'ai fait de mon mieux pour le dessiner).
Prenons cette photo et souvenons-nous des faits suivants:
1. Il y a un attribut _proto_ dans chaque objet.
Il n'y a pas de concept de classe (moisissure) dans le monde JS. Les objets sont dérivés d'un autre objet (proto), il y aura donc un attribut _proto_ dans chaque objet pointant vers son objet prototype. (Reportez-vous à l'objet OBJ défini sous forme littérale dans le coin supérieur gauche. Il ouvre un espace pour stocker les propres propriétés de l'objet en mémoire et génère un _proto_ pointant vers son prototype - l'objet prototype de niveau supérieur.)
2. Chaque fonction a une propriété prototype.
Pourquoi le "constructeur" est-il appelé constructeur? Parce qu'il veut construire un objet. Donc, selon le premier fait ci-dessus, qui est-ce que l'attribut _proto_ du nouvel objet construit pointe? Vous ne pouvez pas pointer vers le constructeur lui-même. Bien qu'il s'agisse également d'un objet, vous ne voulez pas que le nouvel objet hérite des propriétés et des méthodes de la fonction. Par conséquent, chaque constructeur aura un attribut prototype, pointant vers un objet comme prototype du nouvel objet construit par ce constructeur.
3. Les fonctions sont également des objets.
Chaque fonction possède certaines propriétés et méthodes communes, comme appliquer () / call (), etc. Mais comment ces méthodes courantes sont-elles héritées? Comment les fonctions sont-elles créées? Imaginez simplement, tout est un objet, y compris les fonctions, et est un objet construit via un constructeur. Ensuite, selon le deuxième fait ci-dessus, chaque fonction aura également un prototype pointant vers son constructeur. La fonction de ce constructeur est de la fonction et toutes les fonctions en js sont construites à partir de la fonction. Les propriétés générales et les méthodes de fonctions sont stockées sur la fonction d'objet prototype. ProTotype.