Maison >interface Web >js tutoriel >Compréhension approfondie de la série JavaScript (19) : Explication détaillée de la stratégie d'évaluation_Connaissances de base
Présentation
Dans ce chapitre, nous expliquerons la stratégie de transmission de paramètres aux fonctions dans ECMAScript.
En informatique, cette stratégie est généralement appelée « stratégie d'évaluation » (NDLR : Certains disent que cela se traduit par stratégie d'évaluation, et d'autres le traduisent par stratégie d'affectation. En regardant le contenu suivant, je pense que cela s'appelle La stratégie d'affectation est plus appropriée (de toute façon, le titre doit être rédigé comme une stratégie d'évaluation facile à comprendre pour tout le monde), comme la définition de règles pour évaluer ou calculer des expressions dans un langage de programmation. La stratégie consistant à passer des arguments aux fonctions est un cas particulier.
http://dmitrysoshnikov.com/ecmascript/chapter-8-evaluation-strategy/
La raison pour laquelle nous avons écrit cet article est que quelqu'un sur le forum a demandé une explication précise de certaines stratégies de passage de paramètres. Nous avons donné ici les définitions correspondantes, dans l'espoir d'être utiles à tout le monde.
De nombreux programmeurs sont convaincus qu'en JavaScript (et même dans certains autres langages), les objets sont passés par référence, tandis que les types de valeurs primitifs sont passés par valeur. De plus, de nombreux articles mentionnent ce "fait", mais beaucoup de gens le font vraiment. comprenez cette terminologie, et dans quelle mesure est-elle correcte ? Nous l'expliquerons un par un dans cet article.
Théorie générale
Il convient de noter qu'il existe généralement deux stratégies d'affectation dans la théorie de l'affectation : stricte, ce qui signifie que les paramètres sont calculés avant d'entrer dans le programme ; non stricte, ce qui signifie que les paramètres sont calculés en fonction des exigences de calcul (c'est-à-dire le calcul. est équivalent à un calcul différé).
Ensuite, nous considérons ici la stratégie de base de passage des paramètres de fonction, qui est très importante du point de départ d'ECMAScript. La première chose à noter est qu'ECMAScript (et même d'autres langages tels que C, JAVA, Python et Ruby) utilise une stratégie stricte de passage de paramètres.
De plus, l'ordre de calcul des paramètres passés est également très important - dans ECMAScript, il est de gauche à droite, et l'ordre de réflexion (de droite) implémenté dans d'autres langagespeut également être utilisé.
La stratégie de passage strict de paramètres est également divisée en plusieurs sous-stratégies, dont les plus importantes sont abordées en détail dans ce chapitre.
Toutes les stratégies décrites ci-dessous ne sont pas utilisées dans ECMAScript, donc lorsque nous discutons du comportement spécifique de ces stratégies, nous utilisons du pseudocode pour les démontrer.
Passer par valeur
Passez par valeur, comme de nombreux développeurs le savent très bien. La valeur d'un paramètre est une copie de la valeur de l'objet transmis par l'appelant. Changer la valeur du paramètre à l'intérieur de la fonction n'affectera pas l'objet externe (le. paramètre est dans Valeur externe), d'une manière générale, la nouvelle mémoire est réaffectée (on ne fait pas attention à la façon dont la mémoire allouée est implémentée - c'est aussi une pile ou une allocation de mémoire dynamique), la valeur du nouveau bloc mémoire est une copie de l'objet externe et sa valeur est utilisée à l'intérieur de la fonction.
Donnons un exemple général et utilisons la stratégie d'affectation suivante pour le tester. Pensez à une fonction qui accepte 2 paramètres. Le premier paramètre est la valeur de l'objet et le deuxième paramètre est une marque booléenne. l'objet est complètement modifié (réaffecté une valeur à l'objet), ou seules certaines propriétés de l'objet sont modifiées.
Passez par référence
Une autre méthode de passage par référence bien connue ne reçoit pas une copie de la valeur, mais une référence implicite à l'objet, telle que l'adresse de référence externe directe de l'objet. Toute modification des paramètres à l'intérieur de la fonction affectera la valeur de l'objet en dehors de la fonction, car les deux font référence au même objet, c'est-à-dire : à ce moment, le paramètre est équivalent à un alias de l'objet externe.
Pseudo-code :
Appelez en partageant
Tout le monde connaît les deux stratégies ci-dessus, mais la stratégie dont je veux parler ici n'est peut-être pas bien comprise par tout le monde (en fait, c'est une stratégie académique). Cependant, nous verrons bientôt que c'est exactement la stratégie dans laquelle il joue un rôle clé dans les stratégies de passage de paramètres dans ECMAScript.
Il existe également quelques synonymes pour cette stratégie : "passer par objet" ou "passer par partage d'objet".
Cette stratégie a été proposée par Barbara Liskov en 1974 pour le langage de programmation CLU.
Le point clé de cette stratégie est le suivant : la fonction reçoit une copie (copie) de l'objet, et la copie de référence est associée aux paramètres formels et à leurs valeurs.
Nous ne pouvons pas appeler la référence apparaissant ici « passer par référence » car le paramètre reçu par la fonction n'est pas un alias d'objet direct, mais une copie de l'adresse de référence.
La différence la plus importante est : la réaffectation d'une nouvelle valeur au paramètre à l'intérieur de la fonction n'affectera pas l'objet externe (similaire au cas du passage par référence dans l'exemple ci-dessus), mais comme le paramètre est une copie d'adresse, il n'est pas accessible à l'extérieur et à l'intérieur. Le même objet est accessible (par exemple, l'objet externe n'est pas une copie complète comme le passage par valeur), et la modification de la valeur de l'attribut de l'objet paramètre affectera l'objet externe.
//Toujours utiliser cette structure d'objet
barre = {
x : 10,
y : 20
>
// Le passage par contribution affectera l'objet
foo(bar)
// Les propriétés de l'objet ont été modifiées
print(barre) // {x : 100, y : 200}
// La réaffectation n'a aucun effet
foo(bar, vrai)
// Toujours la valeur ci-dessus
print(barre) // {x : 100, y : 200}
Le passage par partage est un cas particulier de passage par valeur
La stratégie pass-by-share est utilisée dans de nombreux langages : Java, ECMAScript, Python, Ruby, Visual Basic, etc. De plus, la communauté Python a adopté cette terminologie, et d'autres langages peuvent également utiliser cette terminologie, car d'autres noms ont tendance à prêter à confusion. Dans la plupart des cas, comme dans Java, ECMAScript ou Visual Basic, cette stratégie est également appelée passage par valeur, ce qui signifie : copie spéciale de référence de valeur.
D'une part, c'est comme ça - le paramètre passé à la fonction n'est qu'un nom de la valeur liée (adresse de référence) et n'affectera pas l'objet externe.
D'un autre côté, ces termes sont vraiment considérés comme faux sans creuser plus profondément, car de nombreux forums parlent de la façon de passer des objets aux fonctions JavaScript).
La théorie générale dit qu'elle est transmise par valeur : mais à l'heure actuelle, la valeur est ce que nous appelons une copie d'adresse (copie), elle n'enfreint donc pas les règles.
En Ruby, cette stratégie est appelée passage par référence. Encore une fois : il n'est pas transmis comme une copie de la grande structure (c'est-à-dire pas transmis par valeur), et d'un autre côté, nous n'avons pas affaire à une référence à l'objet original, et ne pouvons donc pas le modifier ; -le concept de terme peut causer plus de problèmes.
En théorie, il n'existe pas de cas particulier de passage par référence comme le cas particulier de passage par valeur.
Mais il faut encore comprendre que dans les technologies mentionnées ci-dessus (Java, ECMAScript, Python, Ruby, autres), en fait - la stratégie qu'elles utilisent est le passage par partage.
Appuyez sur Partager et pointeur
Pour С/С, cette stratégie est idéologiquement la même que le passage par pointeur par valeur, mais avec une différence importante : cette stratégie peut déréférencer le pointeur ainsi que muter complètement l'objet. Mais en général, un pointeur de valeur (adresse) est alloué à un nouveau bloc mémoire (c'est-à-dire que le bloc mémoire précédemment référencé reste inchangé) ; la modification des attributs de l'objet via le pointeur affectera l'objet externe Adon ;
Donc, et la catégorie pointeur, on peut évidemment voir que celle-ci est transmise par valeur d'adresse. Dans ce cas, le pass-by-share n'est qu'un "sucre syntaxique" qui se comporte comme une affectation de pointeur (mais ne peut pas déréférencer), ou modifie une propriété comme une référence (aucune opération de déréférencement requise). Parfois, il peut être nommé "Pointeurs sécurisés". ".
Cependant, С/С a également un sucre de syntaxe spécial lors du référencement des propriétés d'un objet sans déréférencement explicite du pointeur :
Implémentation ECMAScript
Nous connaissons maintenant la stratégie de passage d'objets en tant que paramètres dans ECMAScript - passage par partage : la modification des propriétés du paramètre affectera l'extérieur, mais la réaffectation n'affectera pas l'objet externe. Cependant, comme nous l'avons mentionné ci-dessus, les développeurs ECMAScript parmi eux l'appellent généralement : passer par valeur, sauf que la valeur est une copie de l'adresse de référence.
L'inventeur de JavaScript, Brendan Ash, a également écrit : Ce qui est transmis est une copie de la référence (copie de l'adresse). Donc, ce que tout le monde sur le forum a dit à propos du passage par valeur est également correct selon cette explication.
Plus précisément, ce comportement peut être compris comme une simple affectation. Nous pouvons voir qu'à l'intérieur se trouve un objet complètement différent, mais il fait référence à la même valeur, c'est-à-dire une copie de l'adresse.
Code ECMAScript :
valeur foo : addr(0xFF) => {x : 100, y : 200} (adresse 0xFF) <= valeur de la barre : addr(0xFF)
Avec la réaffectation, la liaison se fait vers un nouvel identifiant d'objet (nouvelle adresse) sans affecter les objets précédemment liés :
De plus, si l'on considère uniquement le niveau d'abstraction fourni par la norme ECMA-262, tout ce que l'on voit dans l'algorithme c'est la notion de « valeur », et la « valeur » transmise par l'implémentation (peut être une valeur primitive ou un objet), mais selon notre définition ci-dessus, on peut aussi l'appeler "passer par valeur" car l'adresse de référence est aussi une valeur.
Cependant, afin d'éviter tout malentendu (pourquoi les propriétés des objets externes peuvent être modifiées à l'intérieur de la fonction), il reste encore des détails au niveau de l'implémentation qui doivent être pris en compte ici - ce que nous considérons comme un passage par partage, ou dans d'autres mots - en passant par un pointeur sûr, et il est impossible pour un pointeur sûr de déréférencer et de modifier l'objet, mais il peut modifier la valeur d'attribut de l'objet.
Version à terme
Définissons le terme version de cette stratégie dans ECMAScript.
Cela peut être appelé "passage par valeur" - la valeur mentionnée ici est un cas particulier, c'est-à-dire que la valeur est une copie d'adresse. A partir de ce niveau, nous pouvons dire : Tous les objets dans ECMAScript, à l'exception des exceptions, sont transmis par valeur. Il s'agit en fait du niveau abstrait d'ECMAScript.
Ou dans ce cas, cela est spécifiquement appelé "passage par partage". Grâce à cela, vous pouvez voir la différence entre le passage par valeur traditionnel et le passage par référence. Cette situation peut être divisée en 2 situations : 1 : Valeurs originales sont transmis par valeur ; 2 : les objets sont transmis par partage.
La phrase "Convertir un objet en fonction par type référence" n'a rien à voir avec ECMAScript, et elle est fausse.
Conclusion
J'espère que cet article aidera à comprendre plus de détails sur la situation générale et sa mise en œuvre dans ECMAScript. Comme toujours, si vous avez des questions, n'hésitez pas à en discuter.