786 votes

Qu'est-ce que la portée lexicale ?

Quelle est une brève introduction au scoping lexical ?

100 votes

Dans le podcast 58, Joel encourage les questions de ce genre car il souhaite que SO devienne LE lieu où l'on trouve des réponses, même si elles ont déjà été données ailleurs. Cette question est valable, même si on pourrait la formuler de manière un peu plus polie.

0 votes

Et puis surtout fr.wikipedia.org/wiki/Scope_(programmation) qui contient un bel exemple (Pascal/Delphi) de scopes imbriqués dans des procédures imbriquées.

7 votes

@rahul Je comprends que c'est une vieille question. Mais je suis sûr que même en 2009, SO s'attendait à ce que les demandeurs mettent en quelques efforts de base pour le résoudre. En l'état actuel des choses, il ne montre pas tout effort du tout. C'est peut-être pour cela qu'il a été descendu par beaucoup ?

13voto

Robert Rocha Points 4388

IBM le définit comme suit :

La partie d'un programme ou d'une unité de segment dans laquelle une déclaration s'applique. Un identificateur déclaré dans une routine est connu dans cette routine et dans toutes les routines imbriquées. Si une routine imbriquée déclare un élément portant le même nom, l'élément externe n'est pas disponible dans la routine imbriquée. routine imbriquée.

Exemple 1 :

function x() {
    /*
    Variable 'a' is only available to function 'x' and function 'y'.
    In other words the area defined by 'x' is the lexical scope of
    variable 'a'
    */
    var a = "I am a";

    function y() {
        console.log( a )
    }
    y();

}
// outputs 'I am a'
x();

Exemple 2 :

function x() {

    var a = "I am a";

    function y() {
         /*
         If a nested routine declares an item with the same name,
         the outer item is not available in the nested routine.
         */
        var a = 'I am inner a';
        console.log( a )
    }
    y();

}
// outputs 'I am inner a'
x();

11voto

ratiotile Points 705

La portée lexicale signifie qu'une fonction recherche les variables dans le contexte où elle a été définie, et non dans la portée qui l'entoure immédiatement.

Regardez comment la portée lexicale fonctionne dans Lisp si vous voulez plus de détails. La réponse choisie par Kyle Cronin dans Variables dynamiques et lexicales en Common Lisp est beaucoup plus clair que les réponses ici.

Par coïncidence, je n'ai appris cela que dans un cours de Lisp, et il se trouve que cela s'applique aussi à JavaScript.

J'ai exécuté ce code dans la console de Chrome.

// JavaScript               Equivalent Lisp
var x = 5;                //(setf x 5)
console.debug(x);         //(print x)
function print_x(){       //(defun print-x ()
    console.debug(x);     //    (print x)
}                         //)
(function(){              //(let
    var x = 10;           //    ((x 10))
    console.debug(x);     //    (print x)
    print_x();            //    (print-x)
})();                     //)

Sortie :

5
10
5

2 votes

C'est la réponse la plus utile. Si vous êtes d'accord, veuillez voter pour.

4voto

Thomas Points 350

Il y a une partie importante de la conversation qui entoure lexical y cadrage dynamique qui manque : une explication claire de la à vie de la variable scopée - ou quand la variable est accessible.

Le scoping dynamique ne correspond que très vaguement au scoping "global" tel que nous le concevons traditionnellement (la raison pour laquelle j'évoque la comparaison entre les deux est qu'elle a déjà été faite par le passé). mentionné - et je n'aime pas particulièrement le lié à l'explication de l'article) ; il est probablement préférable de ne pas faire la comparaison entre global et dynamique - bien que supposément, selon l'article lié, "...[il] est utile comme substitut aux variables à portée globale".

Donc, en clair, quelle est la distinction importante entre les deux mécanismes de scoping ?

La portée lexicale a été très bien définie dans les réponses ci-dessus : les variables à portée lexicale sont disponibles - ou, accessibles - au niveau local de la fonction dans laquelle elles ont été définies.

Cependant, comme ce n'est pas l'objet du PO, le cadrage dynamique n'a pas reçu beaucoup d'attention et l'attention qu'il a reçue signifie qu'il a probablement besoin d'un peu plus (ce n'est pas une critique des autres réponses, mais plutôt un "oh, cette réponse nous a fait souhaiter qu'il y en ait un peu plus"). Voici donc un peu plus :

Le cadrage dynamique signifie qu'une variable est accessible au programme dans son ensemble pendant la durée de vie de l'appel de fonction - ou pendant l'exécution de la fonction. En réalité, Wikipédia fait un bon travail avec la fonction explication de la différence entre les deux. Pour ne pas l'obscurcir, voici le texte qui décrit le scoping dynamique :

...[D]ans le cas de la portée dynamique (ou portée dynamique), si la portée d'un nom de variable est une est une certaine fonction, alors son champ d'application est la période pendant laquelle la fonction s'exécute : pendant que la fonction s'exécute, la variable existe et est liée à sa variable, mais après le retour de la fonction, le nom de la variable n'existe plus. la fonction, le nom de la variable n'existe plus.

4voto

Kenneth Stoddard Points 626

La portée lexicale fait référence au lexique des identifiants (par exemple, les variables, les fonctions, etc.) visibles à partir de la position actuelle dans la pile d'exécution.

- global execution context
    - foo
    - bar
    - function1 execution context
        - foo2
        - bar2
        - function2 execution context
            - foo3
            - bar3

foo y bar sont toujours dans le lexique des identifiants disponibles car ils sont globaux.

Lorsque function1 est exécuté, il a accès à un lexique de foo2 , bar2 , foo y bar .

Lorsque function2 est exécuté, il a accès à un lexique de foo3 , bar3 , foo2 , bar2 , foo y bar .

La raison pour laquelle les fonctions globales et/ou externes n'ont pas accès aux identifiants d'une fonction interne est que l'exécution de cette fonction n'a pas encore eu lieu et que, par conséquent, aucun de ses identifiants n'a été alloué en mémoire. De plus, une fois que ce contexte interne est exécuté, il est retiré de la pile d'exécution, ce qui signifie que tous ses identifiants ont été collectés et ne sont plus disponibles.

Enfin, c'est pourquoi un contexte d'exécution imbriqué peut TOUJOURS accéder au contexte d'exécution de ses ancêtres et donc pourquoi il a accès à un plus grand lexique d'identifiants.

Voir :

Remerciements particuliers à @robr3rd pour vous aider à simplifier la définition ci-dessus.

3voto

Manngo Points 2894

C'est une vieille question, mais voici mon point de vue.

Lexical La portée (statique) fait référence à la portée d'une variable dans l'environnement de travail. code source .

Dans un langage comme JavaScript, où les fonctions peuvent être transmises, attachées et ré-attachées à divers objets, vous auriez pu penser que la portée dépendrait de la personne qui appelle la fonction à ce moment-là, mais ce n'est pas le cas. Changer la portée de cette façon serait une portée dynamique, et JavaScript ne le fait pas, sauf peut-être avec la fonction this référence à l'objet.

Pour illustrer ce point :

var a='apple';

function doit() {
    var a='aardvark';
    return function() {
        alert(a);
    }
}

var test=doit();
test();

Dans l'exemple, la variable a est définie de manière globale, mais elle est occultée dans l'environnement de l doit() fonction. Cette fonction renvoie une autre fonction qui, comme vous le voyez, s'appuie sur la fonction a en dehors de sa propre portée.

Si vous exécutez ceci, vous constaterez que la valeur utilisée est aardvark pas apple qui, bien qu'elle soit dans le champ d'application du test() n'est pas dans le champ lexical de la fonction originale. C'est-à-dire que la portée utilisée est la portée telle qu'elle apparaît dans le code source, et non la portée où la fonction est réellement utilisée.

Ce fait peut avoir des conséquences fâcheuses. Par exemple, vous pouvez décider qu'il est plus facile d'organiser vos fonctions séparément, puis de les utiliser le moment venu, par exemple dans un gestionnaire d'événements :

var a='apple',b='banana';

function init() {
  var a='aardvark',b='bandicoot';
  document.querySelector('button#a').onclick=function(event) {
    alert(a);
  }
  document.querySelector('button#b').onclick=doB;
}

function doB(event) {
  alert(b);
}

init();

<button id="a">A</button>
<button id="b">B</button>

Cet exemple de code fait un de chaque. Vous pouvez voir qu'en raison du scoping lexical, le bouton A utilise la variable interne, tandis que le bouton B ne le fait pas. Vous pouvez vous retrouver à imbriquer les fonctions plus que vous ne l'auriez souhaité.

Au fait, dans les deux exemples, vous remarquerez également que les variables internes à portée lexicale persistent même si la fonction qui les contient a terminé sa course. C'est ce qu'on appelle fermeture et fait référence à l'accès d'une fonction imbriquée aux variables externes, même si la fonction externe est terminée. JavaScript doit être suffisamment intelligent pour déterminer si ces variables ne sont plus nécessaires et, dans le cas contraire, les récupérer.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X