Maison  >  Article  >  interface Web  >  Explication détaillée du levage en JavaScript

Explication détaillée du levage en JavaScript

黄舟
黄舟original
2017-08-20 10:10:132283parcourir

Les déclarations de fonctions et les déclarations de variables sont toujours implicitement hissées par l'interpréteur JavaScript en haut de la portée qui les contient. L'article suivant vous présente principalement les informations pertinentes sur le levage (levage de variables et levage de déclaration de fonction) en JavaScript. Les amis dans le besoin peuvent s'y référer.

Cet article vous présente principalement le contenu pertinent sur le levage (levage de variables et levage de déclaration de fonction) en JavaScript. Il est partagé pour votre référence et votre étude. Je ne dirai pas grand-chose ci-dessous, jetons un coup d'œil. l'introduction détaillée.

Comment « déplacer » les déclarations/variables de fonctions vers le haut de la portée.

Le terme Hoisting est utilisé dans de nombreux articles de blog JavaScript pour expliquer l'analyse des identifiants. En fait, le mot Hoisting est utilisé pour expliquer comment les déclarations de variables et de fonctions sont hissées au sommet de la fonction ou de la portée globale. Vous ne trouverez ce terme dans aucune documentation JavaScript, et ce que nous appelons Hoisting utilise simplement son sens littéral comme métaphore.

Si vous avez déjà une compréhension de base du fonctionnement de la portée JavaScript, une compréhension plus approfondie de Hoisting peut vous aider à construire une base plus solide. (Remarque de Fool's Wharf : en tant que concept général en JavaScript, le levage de variables et le levage de déclarations de fonctions sont souvent demandés lors des entretiens de développement front-end, ou apparaissent dans les questions de test écrit de développement front-end. Cela montre l'importance de comprendre le levage (levage) .)

Pour mieux comprendre les bases, passons en revue ce que signifie réellement « Levage ». Aussi, pour rappel, JavaScript est un langage interprété, différent des langages compilés, ce qui signifie que le code JS est exécuté ligne par ligne.

Considérez l'exemple suivant :


console.log(notyetdeclared);
// 打印 'undefined'
 
var notyetdeclared = 'now it is declared';
 
hoisting();
 
function hoisting(){
 console.log(notyetdeclared);
 // 打印 'undefined'
 
 var notyetdeclared = 'declared differently';
 
 console.log(notyetdeclared);
 // 打印 'declared differently'
}

Après avoir analysé l'exemple de code ci-dessus, posez quelques questions :

  • Ligne 6, pourquoi cette fonction est-elle accessible avant d'être déclarée ?

  • Ligne 1, aucune erreur n'est renvoyée, est-ce parce que la variable non encore déclarée n'existe pas à ce moment ?

  • À la ligne 4, notyetdeclared a été déclaré dans la portée globale. Pourquoi est-il toujours indéfini lorsqu'il est imprimé à la ligne 9 ?

JavaScript est très logique et tous ces problèmes étranges ont une explication claire.

Commençons par le haut et expliquons que lorsque du code est exécuté en JavaScript, un contexte d'exécution est établi. Il existe deux principaux types de contexte d'exécution en JavaScript : le contexte d'exécution global et le contexte d'exécution de fonction (Remarque de Fool's Pier : prêtez une attention particulière au fait que le contexte d'exécution est différent du contexte dont nous parlons habituellement. Le contexte d'exécution fait référence à la portée , et le contexte d'exécution fait référence à la portée. Le contexte habituel est la valeur pointée par ceci). Puisque JavaScript est basé sur un modèle d’exécution monothread, un seul morceau de code peut être exécuté à la fois.

Pour notre code ci-dessus, le processus est comme indiqué dans la figure :

La pile d'appels de ce qui précède exemple de code :

  • Le programme démarre l'exécution à partir du contexte d'exécution global sur la pile.

  • Lorsque la fonction hoisting() est appelée, un nouveau contexte d'exécution de fonction est poussé sur la pile et le contexte d'exécution global est suspendu.

  • Une fois l'exécution de hoisting() terminée, le contexte d'exécution de hoisting() est extrait de la pile et le contexte d'exécution global est restauré.

Cette procédure est explicite, mais n'explique pas vraiment l'exception que nous avons vue lors de l'exécution de l'exemple de code. Tandis que le contexte d'exécution suit l'exécution du code, l'environnement lexical suit le mappage des identifiants à des variables spécifiques. L'environnement lexical est essentiellement l'implémentation interne du mécanisme de cadrage de JavaScript. Généralement, un environnement lexical est associé à une structure spécifique du code JavaScript, telle qu'une fonction ou un bloc de code de boucle for. Chaque fois qu'une fonction est créée, une référence à l'environnement lexical dans lequel elle a été créée est transmise dans une propriété interne appelée [[Environnement]].

Tous ces termes recouvrent un concept simple et très logique. Laissez-le se décomposer. L'environnement lexical est un nom intéressant utilisé pour garder une trace des variables et des fonctions dans un bloc de code. En plus de suivre les variables locales, les déclarations de fonctions et les paramètres, chaque environnement lexical suit également son environnement lexical parent. Ainsi, l'exemple de code ci-dessus sera analysé comme ceci dans le moteur JavaScript. L'environnement lexical du code ci-dessus est tel qu'illustré dans la figure :

Remarque :

Si vous rencontrez des problèmes de compréhension, veuillez consulter les trois articles suivants :

  • Compréhension approfondie de la portée et du contexte en JavaScript

  • Portée et clôture du concept de base JavaScript

  • Exemple d'analyse de la portée JavaScript

Pour résoudre un identifiant dans un environnement lexical, le moteur JavaScript vérifiera les références à l'environnement actuel. Si aucune référence n'est trouvée, passez à l'environnement externe en utilisant [[environnement]]. Cela continuera jusqu'à ce que l'identifiant soit trouvé ou qu'une erreur « non définie » soit générée.

Fondamentalement, l'exécution du code JavaScript est divisée en deux phases. La première phase enregistre toutes les déclarations de variables et de fonctions dans l'environnement lexical actuel. Une fois terminée, la deuxième phase d’exécution de JavaScript commence !

Donc, pour développer la première phase : elle fonctionne en deux étapes.

  • Scannez le code dans la déclaration de fonction actuelle. Les expressions de fonction et les fonctions fléchées sont ignorées. Pour chaque fonction découverte, une nouvelle fonction est créée et liée à l'environnement à l'aide du nom de la fonction. Si le nom de l'identifiant existe déjà, sa valeur sera écrasée.

  • Scannez ensuite les variables de l'environnement actuel. Recherchez les variables définies à l'aide de var et les variables placées en dehors d'autres fonctions et enregistrez un identifiant dont la valeur est initialisée à undefined . Si l'identifiant est présent, la valeur restera inchangée.

Remarque : Les variables de bloc définies avec let et const sont légèrement différentes de var. Apprenez-en davantage à ce sujet dans un autre article.

Maintenant que vous devriez avoir une certaine compréhension du concept de base de l'environnement lexical, revenons à l'exemple de code et expliquons ces problèmes.

Lors de la définition du contexte global, l'environnement est scanné et la fonction hoisting() est attachée à l'identifiant. Ensuite, à l'étape suivante, la variable notyetdeclared est enregistrée et sa valeur est initialisée à undefined . Suivez cette étape pour continuer à comprendre le code.

Expliquons maintenant les 3 questions soulevées dans l'exemple de code :

Ligne 6, pourquoi la fonction peut-elle être déclarée avant l'accès ?

Dans la phase 1, la fonction hoisting() a été enregistrée dans l'identifiant. Lorsque le code JS commencera à s'exécuter dans le contexte d'exécution global de la phase 2, il recherchera l'environnement lexical de hoisting et. La fonction se trouve avant sa définition.

Ligne 1, aucune erreur n'est renvoyée, est-ce parce que la variable non encore déclarée n'existe pas à ce moment ?

De même, notyetdeclared est enregistré avec l'identifiant et initialisé à undefined dans la phase 1, donc aucune erreur ne sera générée.

Enfin,

À la ligne 4, notyetdeclared a été déclaré dans la portée globale Pourquoi est-il toujours indéfini lorsqu'il est imprimé à la ligne 9 ?

Nous entrons maintenant dans l'environnement de levage de fonctions. Dans la phase 1, notyetdeclared est enregistré et initialisé à undefined car les variables de notyetdeclared n'ont pas encore été enregistrées dans cet environnement lexical. La situation serait différente si la ligne 12 ne contenait pas le mot clé var.

J'espère qu'il est désormais clair que le levage en JavaScript n'est qu'une perspective que nous utilisons pour expliquer les principes qui le sous-tendent. Techniquement parlant, les fonctions et les variables ne bougent nulle part.

Résumé

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