Maison > Article > interface Web > Analyse d'une question d'entretien sur une chaîne de prototypes javascript (détails)
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.
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();
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.
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
Il n'y a fondamentalement rien à expliquer.
Vous pouvez obtenir la réponse en prenant directement la valeur1 [1,2,1] 5
;
Child
Le constructeur a initialement pointé le Child
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
Vous pouvez directement afficher la réponse sur la console pour obtenir <.>11 [1,2,1] 5
Ce qui est déroutant ici, c'est pourquoi la dernière colonne du tableau pointée par this.b est
? >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__ 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.
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() :
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].
2. Comment faire en sorte que le troisième élément du tableau child1.__proto__.b produise également 11 ?
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 :
Ensuite, le code est exécuté : child1.change(); child2.change();
4.parent.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) :
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.
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!