Maison  >  Article  >  interface Web  >  Analyse d'une question d'entretien sur une chaîne de prototypes javascript (détails)

Analyse d'une question d'entretien sur une chaîne de prototypes javascript (détails)

不言
不言original
2018-09-19 17:12:065638parcourir

Le contenu de cet article est une analyse (détaillée) d'une question d'entretien sur la chaîne de prototypes JavaScript. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.

Devant les bases, toutes les compétences sont vaines.

La question est comme ça

Elle nécessite d'écrire la sortie de la console.

function Parent() {
            this.a = 1;
            this.b = [1, 2, this.a];
            this.c = { demo: 5 };
            this.show = function () {
                console.log(this.a , this.b , this.c.demo );
            }
        }
function Child() {
    this.a = 2;
    this.change = function () {
        this.b.push(this.a);
        this.a = this.b.length;
        this.c.demo = this.a++;
    }
}
        Child.prototype = new Parent(); 
        var parent = new Parent();
        var child1 = new Child();
        var child2 = new Child();
        child1.a = 11;
        child2.a = 12;
        parent.show();
        child1.show();
        child2.show();
        child1.change();
        child2.change();
        parent.show();
        child1.show();
        child2.show();

Les points de connaissance impliqués dans la question

  • Cela pointe vers

  • Chaîne de prototypes

  • Héritage de classe

  • Primitive types et références Différences de types
    Chaque point de connaissance peut être extrait pour une recherche spéciale distincte.

Détails des points de connaissances nécessaires pour résoudre le problème

1 Le constructeur a un attribut prototype, pointant vers l'objet prototype du constructeur, et le. l'instance partagera le même Un objet prototype ;

2. Lorsqu'une instance est générée, une nouvelle mémoire tas sera générée dans la mémoire. Les opérations générales sur l'instance n'affecteront pas les autres instances, car elles occupent des espaces différents. dans la mémoire du tas et ne s'affectent pas. ;

3 Chaque instance a un prototype implicite __proto__ qui pointe vers l'objet prototype du constructeur

4. Les situations sont les suivantes :

4.1 Lorsqu'elle est appelée en tant que méthode objet, elle pointe vers celui qui l'appelle (cette question implique principalement cet article)

4.2 Lorsqu'elle est appelée en tant que fonction, elle pointe vers la fenêtre de variable globale de niveau supérieur

4.3 En tant que constructeur Lorsqu'une fonction est appelée, c'est-à-dire lorsque l'opérateur new génère une instance, celle-ci dans le constructeur pointe vers l'instance

4.4 Dans le méthodes d'appel et d'application, la liaison de ce qui est spécifié est affichée comme le contexte spécifié

5. Méthode quantitative littérale (il existe également des informations qui traduisent le littéral en quantité directe. Je pense personnellement que cette dernière traduction est en fait plus intuitif et plus vivant). Lors de l'attribution d'objets et de tableaux (l'essence des tableaux est également des objets), ce sont toutes des références, c'est-à-dire que les ressources sont générées dans la mémoire tas. La mémoire de pile génère des variables, puis les variables pointent vers le tas. adresse de la ressource.

6. Les règles de recherche de la chaîne de prototypes suivent le principe du chemin le plus court, c'est-à-dire qu'il faut d'abord rechercher les attributs de l'instance, puis rechercher les attributs spécifiés le long de la chaîne de prototypes jusqu'à ce que Object.prototype et null soient présents. fin de la chaîne de prototypes. Si l'instance elle-même et si la propriété recherchée n'existe pas dans toute la chaîne de prototypes, undefined sera renvoyé

7 La différence détaillée entre les instructions d'affectation pour l'affectation de valeur primitive et le type de référence. mission

Commencez à analyser la question

1.parent.show()

Il n'y a fondamentalement rien à expliquer.
Vous pouvez obtenir la réponse en prenant directement la valeur1 [1,2,1] 5;

2.child1.show()

Child Le constructeur a initialement pointé le Child
Analyse d'une question d'entretien sur une chaîne de prototypes javascript (détails) de
Dans la question, l'objet prototype de la classe Child pointait vers une instance de la classe Parent. en programmation orientée objet JavaScript. 🎜>Une des méthodes d'héritage. Il convient de noter ici que pointe vers l'instance Child.prototype de Parent, pas vers la classe parent Parent
Analyse d'une question d'entretien sur une chaîne de prototypes javascript (détails) Vous pouvez directement afficher la réponse sur la console pour obtenir <.>
11 [1,2,1] 5
Analyse d'une question d'entretien sur une chaîne de prototypes javascript (détails)Ce qui est déroutant ici, c'est pourquoi la dernière colonne du tableau pointée par this.b est

au lieu de

 ? >1 vient en premier Regardez à quoi ressemble child1 : 11


Lorsque la méthode child1.show() est exécutée, puisque child1, en tant qu'instance de Child, a l'attribut a, donc dans la méthode show() this.a pointera directement sur la valeur de cet attribut, qui est 11, au lieu de continuer le long de la chaîne de prototypes pour obtenir l'attribut a sur l'objet pointé par __proto__ Analyse d'une question d'entretien sur une chaîne de prototypes javascript (détails) cherche ensuite this.b, car child1 Il n'y a pas d'attribut b, donc l'attribut b sur le parent sera récupéré le long de la chaîne du prototype. Sa valeur est un tableau. Les deux premiers éléments sont des constantes, ce qui n'a rien à dire. Le dernier élément du tableau est une référence, et le pointeur ici ne l'est pas. Ce n'est pas un pointeur dynamique, car il a été exécuté une fois lors de l'étape new Parent() et il est déterminé qu'il pointe vers la ressource pointée par. parent.a, qui est la ressource pointée par l'attribut a dans child1.__proto__, c'est-à-dire la valeur 1.

Réflexion étendue

Il est à noter que :

Du point de vue du code, l'enfant1.__proto__. b array est Les trois éléments pointent vers child1.__proto__.a, donc si nous modifions la valeur de child1.__proto__.a à ce moment, cela affectera-t-il le résultat de child1.show() :

  1. La réponse est que cela n'a aucun impact. Pourquoi les attributs qui semblent pointer vers la même adresse ont-ils des valeurs différentes ? Parce que lorsque l'instance parent est générée, this.a pointe vers une valeur primitive 2, donc le troisième élément de this.b se voit en fait attribuer une valeur primitive, donc cela ressemble à première vue à une affectation de type référence, mais ce n'est pas le cas. . L'attribution de valeurs primitives ouvrira un nouvel espace de stockage, rendant les valeurs de this.a et this.b[2] égales, mais pointant vers des adresses différentes dans la mémoire du tas. Pour des explications plus détaillées, veuillez consulter les articles de blog recommandés dans [Lecture approfondie]. Analyse d'une question d'entretien sur une chaîne de prototypes javascript (détails)


    2. Comment faire en sorte que le troisième élément du tableau child1.__proto__.b produise également 11 ?

  2. Modifiez-le après l'instanciation
Parce que dans Dans la définition de la classe Parent, le troisième élément du tableau d'attributs b pointe vers la valeur de l'attribut a, ce qui signifie que cette référence est pointée dynamiquement vers avant que le Parent ne soit instancié, donc tant que la valeur de this.a dans le la définition de la classe est modifiée avant l'instanciation du parent, vous pouvez obtenir l'effet souhaité s'il a été instancié dans le parent, vous ne pouvez modifier explicitement que la valeur de l'attribut *.b[2].

Synchronisation de la méthode Get/set

Une autre façon consiste à définir la méthode get/set pour l'attribut a Oui, chaque fois que la valeur de l'attribut a change, la valeur de b[2] est modifiée de manière synchrone. . Le code et les résultats d'exécution sont les suivants :


  • Analyse d'une question d'entretien sur une chaîne de prototypes javascript (détails)
    Analyse d'une question d'entretien sur une chaîne de prototypes javascript (détails)

    3.child2. show( )
Si vous comprenez l'explication ci-dessus, vous pouvez obtenir la réponse par la même méthode ici : 12 [1,2,1] 5

Ensuite, le code est exécuté : child1.change(); child2.change();

4.parent.show()

parent est une instance de la classe Parent et Child.prorotype pointe vers une autre instance de la classe Parent. Les deux sont deux ressources dans la mémoire tas et ne s'affectent pas, donc les opérations ci-dessus n'affectent pas le parent. instance, et les résultats de sortie restent inchangés : 1 [1,2,1] 5;
5.child1.show(),child2.show()

Quels changements se sont produits après que child1 ait exécuté la méthode change() ?

this.b. push(this.a)
En raison des caractéristiques de pointage dynamique de this, this.b pointera vers le tableau b sur Child.prototype, et this.a pointera vers l'attribut a de child1, donc Child.prototype. b devient Il devient [1,2,1,11];

this.a = this.b.length
Les points de this.a et this.b dans this sont les mêmes que La phrase précédente est cohérente, donc le résultat est que child1.a devient 4;

this.c.demo = this.a++
Puisque les propres attributs de child1 n'ont pas c est l'attribut, donc this.c ici pointera vers Child.prototype.c La valeur de this.a est 4, qui est un type primitif, donc. l'opération d'affectation attribuera directement la valeur à Child.prototype.c Le résultat de la démo est 4, et this.a augmente alors à 5(4 + 1 = 5). .

Ensuite, child2 exécute la méthode change(), et child2 et child1 sont tous deux des instances de la classe Child, donc leurs chaînes de prototypes pointent vers le même objet prototype Child.prototype, qui est la même instance parent, donc toutes les instructions dans child2.change() qui affectent l'objet prototype affecteront le résultat final de child1

this.b.push(this.a)

En raison des caractéristiques de pointage dynamique de this, this.b pointera vers Pour le tableau b sur Child.prototype, this.a pointera vers l'attribut a de child2, donc Child.prototype.b devient

[1,2,1,11,12];

this.a = this.b.length
Les directions de this.a et this. b dans cette instruction sont cohérents avec la phrase précédente, donc le résultat est child2.a devient 5 ;

this.c.demo = this.a++
Puisque le propre attribut de child2 le fait n'a pas l'attribut c, this.c pointera ici vers Child.prototype.c, donc le résultat de l'exécution est Child. La valeur de .prototype.c.demo passe à la valeur 5 de child2.a, et child2.a finit par incrémenter à 6 (5 + 1 = 6).

Ensuite, exécutez la commande de sortie et le résultat final sera affiché :
child1.show():5 [1,2,1 ,11,12] 5
child2.show():6 [1,2,1,11 ,12] 5

Pensée étendue
Quand je résolvait le problème, j'ai fait une erreur dans this.c.demo = this.a++ Je pensais qu'une référence serait passée ici, mais en fait, une valeur a été passée Après analyse, nous comprenons cela parce que this.a pointe. à une valeur d'origine, cela équivaut à attribuer la valeur d'origine à l'attribut d'objet, donc la valeur de child.c.demo ne sera plus affectée par les modifications de child.a après l'affectation. Si child.a est un type référence, à quoi ressemblera le résultat ?
Nous apportons quelques modifications au code source et pointons child.a vers un objet (c'est-à-dire un type de référence) : Analyse d'une question d'entretien sur une chaîne de prototypes javascript (détails)
Ensuite, après l'avoir exécuté, nous constaterons que la valeur de Child.prototype.c suivra la valeur de child1.a change avec les changements, car la valeur de child1.a est un type de référence à ce moment-là, et le processus d'affectation fera que Child.prototype.c et child1.a pointent vers l'adresse de l'espace mémoire de la même ressource . Pour une explication plus détaillée des types originaux et des types de référence, vous pouvez vous référer au blog dans Extended Reading à la fin de cet article.

Récolte et réflexion

1. Les connaissances de base sont intrinsèquement des détails dispersés et doivent être apprises avec une attitude tenace.

2. Les connaissances de base sont les plus ennuyeuses, et c'est aussi ce qui creuse vraiment le fossé entre les gens. C'est aussi le seuil qu'il faut franchir si l'on veut entrer dans une grande usine. urgent. Nous sommes également des novices. Certaines personnes deviendront des architectes front-end après 3 à 5 ans. Certaines personnes utiliseront encore une infinité de nouveaux frameworks pour lier des événements à des boutons après 3 à 5 ans. Celui que vous voulez être dépend des efforts que vous déployez. à mettre dedans. , la plupart du temps, il n'y a rien de mal à cela. La fondation est très importante ! Très important ! Très important !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn