Quelle est la portée lexicale?


682

Qu'est-ce qu'une brève introduction à la portée lexicale?


89
Dans le podcast 58, Joel encourage les questions comme celles-ci car il veut que SO devienne LE lieu de réponses, même si elles ont été répondues ailleurs. C'est une question valable, même si on pourrait la poser un peu plus poliment.
Ralph M. Rickenbach le

5
@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 déploient des efforts de base pour le résoudre. En l'état, il ne montre aucun effort. Peut-être, c'est pourquoi il a été rejeté par beaucoup?
PP

13
Il est possible que le demandeur ne parle pas (ou ne parle pas) couramment l'anglais lors de la rédaction de cette question
Martin

28
La question est polie, il dit juste ce qu'il veut. Vous êtes libre de répondre. Pas besoin d'une politesse insensible ici.
Markus Siebeneicher

25
Je pense que des questions comme celles-ci sont excellentes car elles créent du contenu pour SO. OMI, peu importe si la question n'a pas d'effort ... les réponses auront un excellent contenu et c'est ce qui compte sur ce babillard.
Jwan622

Réponses:


687

Je les comprends à travers des exemples. :)

Tout d'abord, la portée lexicale (également appelée portée statique ), dans une syntaxe de type C:

void fun()
{
    int x = 5;

    void fun2()
    {
        printf("%d", x);
    }
}

Chaque niveau intérieur peut accéder à ses niveaux extérieurs.

Il existe une autre façon, appelée portée dynamique utilisée par la première implémentation de Lisp , toujours dans une syntaxe de type C:

void fun()
{
    printf("%d", x);
}

void dummy1()
{
    int x = 5;

    fun();
}

void dummy2()
{
    int x = 10;

    fun();
}

Ici, vous funpouvez accéder xà dummy1ou dummy2, ou à n'importe xquelle fonction qui appelle funavec xdéclaré en elle.

dummy1();

imprimera 5,

dummy2();

imprimera 10.

Le premier est appelé statique car il peut être déduit au moment de la compilation, et le second est appelé dynamique car la portée externe est dynamique et dépend de l'appel en chaîne des fonctions.

Je trouve la portée statique plus facile pour l'œil. La plupart des langues ont fini par suivre cette voie, même Lisp (peut faire les deux, non?). La portée dynamique revient à transmettre les références de toutes les variables à la fonction appelée.

Pour illustrer pourquoi le compilateur ne peut pas déduire la portée dynamique externe d'une fonction, considérons notre dernier exemple. Si nous écrivons quelque chose comme ça:

if(/* some condition */)
    dummy1();
else
    dummy2();

La chaîne d'appel dépend d'une condition d'exécution. Si c'est vrai, alors la chaîne d'appel ressemble à:

dummy1 --> fun()

Si la condition est fausse:

dummy2 --> fun()

La portée externe de fundans les deux cas est l'appelant plus l'appelant de l'appelant et ainsi de suite .

Juste pour mentionner que le langage C ne permet pas les fonctions imbriquées ni la portée dynamique.


19
Je voudrais également souligner un tutoriel très très facile à comprendre que je viens de trouver. L'exemple d'Arak est sympa, mais peut être trop court pour quelqu'un qui a besoin de plus d'exemples (en fait, en comparant avec d'autres langues ..). Regarde. Il est important de comprendre cela , car ce mot-clé nous conduira à comprendre la portée lexicale. howtonode.org/what-is-this
CppLearner

9
C'est une bonne réponse. Mais la question est étiquetée avec JavaScript. Par conséquent, je pense que cela ne devrait pas être marqué comme la réponse acceptée. La portée lexicale spécifiquement dans JS est différente
Boyang

6
Réponse extrêmement bonne. Je vous remercie. @Boyang, je ne suis pas d'accord. Je ne suis pas un codeur Lisp, mais j'ai trouvé l'exemple Lisp utile, car c'est un exemple de portée dynamique, que vous n'obtenez pas dans JS.
dudewad

4
Au départ, je pensais que l'exemple était un code C valide et je ne savais pas s'il y avait une portée dynamique en C. Peut-être que la clause de non-responsabilité à la fin pourrait être déplacée avant l'exemple de code?
Yangshun Tay

2
C'est toujours une réponse très utile mais je pense que @Boyang est correct. Cette réponse fait référence au «niveau», qui correspond davantage à la portée du bloc que C a. JavaScript par défaut n'a pas de portée au niveau du bloc, donc à l'intérieur d'une forboucle est le problème typique. La portée lexicale de JavaScript est uniquement au niveau de la fonction, sauf si l'ES6 letou constest utilisé.
icc97

275

Essayons la définition la plus courte possible:

La portée lexicale définit la façon dont les noms de variable sont résolus dans les fonctions imbriquées: les fonctions internes contiennent la portée des fonctions parent même si la fonction parent est retournée .

C'est tout ce qu'il y a à faire!


21
La dernière partie: "même si la fonction parent est revenue" est appelée fermeture.
Juanma Menendez

1
Compris la portée et la clôture lexicale en une seule phrase. Merci!!
Donjon

63
var scope = "I am global";
function whatismyscope(){
   var scope = "I am just a local";
   function func() {return scope;}
   return func;
}

whatismyscope()()

Le code ci-dessus renverra "Je suis juste un local". Il ne reviendra pas "Je suis un global". Parce que la fonction func () compte où est initialement défini ce qui est dans le cadre de la fonction whatismyscope.

Cela ne dérangera pas quel que soit son nom (la portée globale / même dans une autre fonction), c'est pourquoi la valeur de la portée globale Je suis global ne sera pas imprimée.

C'est ce qu'on appelle la portée lexicale où «les fonctions sont exécutées en utilisant la chaîne de portée qui était en vigueur au moment de leur définition » - selon le guide de définition JavaScript.

La portée lexicale est un concept très très puissant.

J'espère que cela t'aides..:)


3
c'est une très belle explication je veux ajouter une chose de plus si vous écrivez la fonction func () {return this.scope;} alors il retournera "Je suis global" utilisez simplement ce mot-clé et votre portée obtiendra le changement
Rajesh Kumar Bhawsar

41

La portée lexicale (AKA statique) fait référence à la détermination de la portée d'une variable uniquement en fonction de sa position dans le corpus textuel du code. Une variable fait toujours référence à son environnement de niveau supérieur. Il est bon de le comprendre par rapport à la portée dynamique.


41

La portée définit la zone, où les fonctions, les variables et autres sont disponibles. La disponibilité d'une variable par exemple est définie dans son contexte, disons la fonction, le fichier ou l'objet dans lequel ils sont définis. Nous appelons généralement ces variables locales.

La partie lexicale signifie que vous pouvez dériver la portée de la lecture du code source.

La portée lexicale est également appelée portée statique.

La portée dynamique définit des variables globales qui peuvent être appelées ou référencées de n'importe où après avoir été définies. Parfois, elles sont appelées variables globales, même si les variables globales dans la plupart des langages de programmation sont de portée lexicale. Cela signifie, il peut être dérivé de la lecture du code que la variable est disponible dans ce contexte. Peut-être qu'il faut suivre une clause uses ou includes pour trouver l'instatiation ou la définition, mais le code / compilateur connaît la variable à cet endroit.

Dans la portée dynamique, en revanche, vous recherchez d'abord dans la fonction locale, puis vous recherchez dans la fonction qui a appelé la fonction locale, puis vous recherchez dans la fonction qui a appelé cette fonction, et ainsi de suite, dans la pile des appels. "Dynamique" fait référence au changement, dans la mesure où la pile d'appels peut être différente à chaque fois qu'une fonction donnée est appelée, et donc la fonction peut frapper différentes variables selon d'où elle est appelée. (voir ici )

Pour voir un exemple intéressant de portée dynamique, voir ici .

Pour plus de détails, voir ici et ici .

Quelques exemples en Delphi / Object Pascal

Delphi a une portée lexicale.

unit Main;
uses aUnit;  // makes available all variables in interface section of aUnit

interface

  var aGlobal: string; // global in the scope of all units that use Main;
  type 
    TmyClass = class
      strict private aPrivateVar: Integer; // only known by objects of this class type
                                    // lexical: within class definition, 
                                    // reserved word private   
      public aPublicVar: double;    // known to everyboday that has access to a 
                                    // object of this class type
    end;

implementation

  var aLocalGlobal: string; // known to all functions following 
                            // the definition in this unit    

end.

Delphi se rapproche le plus de la portée dynamique est la paire de fonctions RegisterClass () / GetClass (). Pour son utilisation voir ici .

Disons que l'heure à laquelle RegisterClass ([TmyClass]) est appelé pour enregistrer une certaine classe ne peut pas être prédite en lisant le code (il est appelé dans une méthode de clic de bouton appelée par l'utilisateur), le code appelant GetClass ('TmyClass') obtiendra un résultat ou non. L'appel à RegisterClass () ne doit pas nécessairement être dans la portée lexicale de l'unité utilisant GetClass ();

Une autre possibilité pour la portée dynamique sont les méthodes anonymes (fermetures) dans Delphi 2009, car elles connaissent les variables de leur fonction d'appel. Il ne suit pas le chemin d'appel à partir de là de manière récursive et n'est donc pas entièrement dynamique.


2
En fait, privé est accessible dans toute l'unité où la classe est définie. C'est pourquoi "Strict private" a été introduit dans D2006.
Marco van de Voort

2
+1 pour un langage simple (par opposition à un langage compliqué et à des exemples sans beaucoup de description)
Pop

36

J'adore les réponses complètes et indépendantes de la langue de personnes comme @Arak. Puisque cette question a été taguée JavaScript , je voudrais ajouter quelques notes très spécifiques à cette langue.

En JavaScript, nos choix de cadrage sont les suivants:

  • en l'état (aucun ajustement de la portée)
  • lexical var _this = this; function callback(){ console.log(_this); }
  • lié callback.bind(this)

Il convient de noter, je pense, que JavaScript n'a pas vraiment de portée dynamique . .bindajuste le thismot clé, et c'est proche, mais pas techniquement le même.

Voici un exemple illustrant les deux approches. Vous effectuez cette opération chaque fois que vous décidez de la façon d'étendre les rappels, cela s'applique donc aux promesses, aux gestionnaires d'événements, etc.

Lexical

Voici ce que vous pourriez appeler Lexical Scopingdes rappels en JavaScript:

var downloadManager = {
  initialize: function() {
    var _this = this; // Set up `_this` for lexical access
    $('.downloadLink').on('click', function () {
      _this.startDownload();
    });
  },
  startDownload: function(){
    this.thinking = true;
    // Request the file from the server and bind more callbacks for when it returns success or failure
  }
  //...
};

Lié

Une autre façon d'étendre est d'utiliser Function.prototype.bind:

var downloadManager = {
  initialize: function() {
    $('.downloadLink').on('click', function () {
      this.startDownload();
    }.bind(this)); // Create a function object bound to `this`
  }
//...

Pour autant que je sache, ces méthodes sont équivalentes sur le plan du comportement.


L'utilisation bindn'affecte pas la portée.
Ben Aston

12

Portée lexicale: les variables déclarées en dehors d'une fonction sont des variables globales et sont visibles partout dans un programme JavaScript. Les variables déclarées à l'intérieur d'une fonction ont une portée de fonction et ne sont visibles que par le code qui apparaît à l'intérieur de cette fonction.


12

IBM le définit comme:

Portion d'une unité de programme ou de segment à laquelle s'applique une déclaration. Un identifiant 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 du même nom, l'élément externe n'est pas disponible dans la 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();

8

La portée lexicale signifie que dans un groupe de fonctions imbriquées, les fonctions internes ont accès aux variables et autres ressources de leur portée parent . Cela signifie que les fonctions enfants sont lexicalement liées au contexte d'exécution de leurs parents. La portée lexicale est parfois également appelée portée statique .

function grandfather() {
    var name = 'Hammad';
    // 'likes' is not accessible here
    function parent() {
        // 'name' is accessible here
        // 'likes' is not accessible here
        function child() {
            // Innermost level of the scope chain
            // 'name' is also accessible here
            var likes = 'Coding';
        }
    }
}

La chose que vous remarquerez à propos de la portée lexicale est qu'elle fonctionne en avant, ce qui signifie que le nom est accessible par les contextes d'exécution de ses enfants. Mais il ne fonctionne pas en arrière pour ses parents, ce qui signifie que la variable likesn'est pas accessible à ses parents.

Cela nous indique également que les variables portant le même nom dans des contextes d'exécution différents gagnent la priorité du haut vers le bas de la pile d'exécution. Une variable, ayant un nom similaire à une autre variable, dans la fonction la plus interne (contexte le plus haut de la pile d'exécution) aura une priorité plus élevée.

Notez que cela est tiré d' ici .


8

En langage simple, la portée lexicale est une variable définie en dehors de votre portée ou la portée supérieure est automatiquement disponible à l'intérieur de votre portée, ce qui signifie que vous n'avez pas besoin de la passer là-bas.

Exemple:

let str="JavaScript";

const myFun = () => {
    console.log(str);
}

myFun();

// Sortie: JavaScript


2
La réponse la plus courte et la meilleure pour moi avec un exemple. Aurait pu être ajouté que les fonctions fléchées de l'ES6 résolvent le problème avec bind. Avec eux, le bindn'est plus nécessaire. Pour plus d'informations sur cette modification, consultez stackoverflow.com/a/34361380/11127383
Daniel Danielecki

4

Il y a une partie importante de la conversation entourant la portée lexicale et dynamique qui manque: une explication claire de la durée de vie de la variable portée - ou quand la variable est accessible.

Le cadrage dynamique ne correspond que très vaguement au cadrage "global" dans la façon dont nous y pensons traditionnellement (la raison pour laquelle j'évoque la comparaison entre les deux est qu'il a déjà été mentionné - et je n'aime pas particulièrement l'explication de l'article lié ); il est probablement préférable que nous ne fassions pas la comparaison entre global et dynamique - bien que soi-disant, selon l'article lié, "... [il] est utile comme substitut aux variables de portée globale."

Donc, en langage simple, quelle est la distinction importante entre les deux mécanismes de cadrage?

La portée lexicale a été très bien définie tout au long des réponses ci-dessus: des variables de portée lexicale sont disponibles - ou accessibles - au niveau local de la fonction dans laquelle elle a été définie.

Cependant - comme ce n'est pas l'objectif du PO - la portée dynamique n'a pas reçu beaucoup d'attention et l'attention qu'elle a reçue signifie qu'elle 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 "). Alors, voici un peu plus:

La portée dynamique signifie qu'une variable est accessible au plus grand programme pendant la durée de vie de l'appel de fonction - ou, pendant l'exécution de la fonction. Vraiment, Wikipedia fait vraiment du bon travail avec l' explication de la différence entre les deux. Afin de ne pas l'obscurcir, voici le texte qui décrit la portée dynamique:

... [I] n portée dynamique (ou portée dynamique), si la portée d'un nom de variable est une certaine fonction, alors sa portée est la période pendant laquelle la fonction s'exécute: pendant que la fonction est en cours d'exécution, le nom de la variable existe et est lié à sa variable, mais après le retour de la fonction, le nom de la variable n'existe pas.


3

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

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

Par coïncidence, je ne l'ai appris que dans une classe Lisp, et cela s'applique également à 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)
})();                     //)

Production:

5
10
5

3

Une portée lexicale en JavaScript signifie qu'une variable définie en dehors d'une fonction peut être accessible à l'intérieur d'une autre fonction définie après la déclaration de variable. Mais l'inverse n'est pas vrai; les variables définies à l'intérieur d'une fonction ne seront pas accessibles en dehors de cette fonction.

Ce concept est largement utilisé dans les fermetures en JavaScript.

Disons que nous avons le code ci-dessous.

var x = 2;
var add = function() {
    var y = 1;
    return x + y;
};

Maintenant, lorsque vous appelez add () -> cela affichera 3.

Ainsi, la fonction add () accède à la variable globale xqui est définie avant la fonction de méthode add. Ceci est appelé en raison de la portée lexicale en JavaScript.


Considérez que l'extrait de code était destiné à un langage à portée dynamique. Si la add()fonction était appelée immédiatement après l'extrait de code donné, elle afficherait également 3. La portée lexicale ne signifie pas simplement qu'une fonction peut accéder à des variables globales en dehors du contexte local. Ainsi, l'exemple de code n'aide vraiment pas à montrer ce que signifie la portée lexicale. L'affichage de la portée lexicale dans le code a vraiment besoin d'un contre-exemple ou au moins d'une explication d'autres interprétations possibles du code.
C Perkins

2

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

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

fooet barsont toujours dans le lexique des identifiants disponibles car ils sont globaux.

Quand function1est exécuté, il a accès à un lexique foo2, bar2, fooet bar.

Quand function2est exécuté, il a accès à un lexique foo3, bar3, foo2, bar2, fooet bar.

La raison pour laquelle les fonctions globales et / ou externes n'ont pas accès aux identifiants de fonctions internes est que l'exécution de cette fonction n'a pas encore eu lieu et, par conséquent, aucun de ses identifiants n'a été alloué à la mémoire. De plus, une fois ce contexte interne exécuté, il est supprimé de la pile d'exécution, ce qui signifie que tous ses identifiants ont été récupéré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:

Un merci spécial à @ robr3rd pour son aide à simplifier la définition ci-dessus.


1

Voici un angle différent sur cette question que nous pouvons obtenir en prenant du recul et en examinant le rôle de la portée dans le cadre plus large de l'interprétation (exécution d'un programme). En d'autres termes, imaginez que vous construisiez un interpréteur (ou compilateur) pour une langue et que vous étiez responsable du calcul de la sortie, compte tenu d'un programme et de certaines entrées.

L'interprétation implique le suivi de trois choses:

  1. État - à savoir, les variables et les emplacements de mémoire référencés sur le tas et la pile.

  2. Opérations sur cet état - à savoir, chaque ligne de code de votre programme

  3. L' environnement dans lequel une opération donnée s'exécute, à savoir la projection d' état sur une opération.

Un interpréteur commence à la première ligne de code d'un programme, calcule son environnement, exécute la ligne dans cet environnement et capture son effet sur l'état du programme. Il suit ensuite le flux de contrôle du programme pour exécuter la ligne de code suivante et répète le processus jusqu'à la fin du programme.

La façon dont vous calculez l'environnement pour toute opération se fait à travers un ensemble formel de règles définies par le langage de programmation. Le terme "liaison" est fréquemment utilisé pour décrire la mise en correspondance de l'état global du programme avec une valeur dans l'environnement. Notez que par «état global», nous ne voulons pas dire l'état global, mais plutôt la somme totale de chaque définition accessible, à tout moment de l'exécution).

C'est le cadre dans lequel le problème de délimitation est défini. Passons maintenant à la partie suivante de nos options.

  • En tant qu'implémenteur de l'interpréteur, vous pouvez simplifier votre tâche en rendant l'environnement aussi proche que possible de l'état du programme. En conséquence, l'environnement d'une ligne de code serait simplement défini par l'environnement de la ligne de code précédente avec les effets de cette opération qui lui seraient appliqués, que la ligne précédente soit une affectation, un appel de fonction, un retour d'une fonction, ou une structure de contrôle telle qu'une boucle while.

C'est l'essentiel de la portée dynamique , dans laquelle l'environnement dans lequel tout code s'exécute est lié à l'état du programme tel que défini par son contexte d'exécution.

  • Ou , vous pourriez penser à un programmeur utilisant votre langage et simplifier sa tâche de garder une trace des valeurs qu'une variable peut prendre. Il y a beaucoup trop de chemins et trop de complexité impliqués dans le raisonnement sur le résultat de la totalité de l'exécution passée. La portée lexicale y contribue en restreignant l'environnement actuel à la portion d'état définie dans le bloc, la fonction ou toute autre unité de portée actuelle, et son parent (c'est-à-dire le bloc contenant l'horloge actuelle ou la fonction qui a appelé la fonction actuelle).

En d'autres termes, avec l'étendue lexicale, l'environnement que tout code voit est lié à l'état associé à une étendue définie explicitement dans le langage, comme un bloc ou une fonction.


0

Question ancienne, mais voici mon point de vue.

La portée lexicale (statique) fait référence à la portée d'une variable dans le code source .

Dans un langage comme JavaScript, où les fonctions peuvent être transmises et attachées et reconnectées à divers objets, vous pourriez avoir bien que cette portée dépende de qui appelle la fonction à l'époque, 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 éventuellement avec la thisréférence d'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 aest définie globalement, mais ombrée dans la doit()fonction. Cette fonction renvoie une autre fonction qui, comme vous le voyez, repose sur lea variable en dehors de sa propre portée.

Si vous exécutez cela, vous constaterez que la valeur utilisée n'est aardvarkpas celle applequi, bien qu'elle soit dans la portée de la test()fonction, n'est pas dans la portée lexicale de la fonction d'origine. Autrement dit, la portée utilisée est la portée telle qu'elle apparaît dans le code source, pas la portée où la fonction est réellement utilisée.

Ce fait peut avoir des conséquences gênantes. Par exemple, vous pourriez décider qu'il est plus facile d'organiser vos fonctions séparément, puis de les utiliser le moment venu, comme 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 l'un de chacun. Vous pouvez voir qu'en raison de la portée lexicale, le bouton Autilise la variable interne, tandis que le boutonB contrairement au . Vous pouvez finir par imbriquer des fonctions plus que vous ne l'auriez souhaité.

Soit dit en passant, dans les deux exemples, vous remarquerez également que les variables de portée lexicale interne persistent même si la fonction de fonction contenant a suivi son cours. Ceci est appelé 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, peut les récupérer.


-1

J'apprends normalement par l'exemple, et voici un petit quelque chose:

const lives = 0;

function catCircus () {
    this.lives = 1;
    const lives = 2;

    const cat1 = {
        lives: 5,
        jumps: () => {
            console.log(this.lives);
        }
    };
    cat1.jumps(); // 1
    console.log(cat1); // { lives: 5, jumps: [Function: jumps] }

    const cat2 = {
        lives: 5,
        jumps: () => {
            console.log(lives);
        }
    };
    cat2.jumps(); // 2
    console.log(cat2); // { lives: 5, jumps: [Function: jumps] }

    const cat3 = {
        lives: 5,
        jumps: () => {
            const lives = 3;
            console.log(lives);
        }
    };
    cat3.jumps(); // 3
    console.log(cat3); // { lives: 5, jumps: [Function: jumps] }

    const cat4 = {
        lives: 5,
        jumps: function () {
            console.log(lives);
        }
    };
    cat4.jumps(); // 2
    console.log(cat4); // { lives: 5, jumps: [Function: jumps] }

    const cat5 = {
        lives: 5,
        jumps: function () {
            var lives = 4;
            console.log(lives);
        }
    };
    cat5.jumps(); // 4
    console.log(cat5); // { lives: 5, jumps: [Function: jumps] }

    const cat6 = {
        lives: 5,
        jumps: function () {
            console.log(this.lives);
        }
    };
    cat6.jumps(); // 5
    console.log(cat6); // { lives: 5, jumps: [Function: jumps] }

    const cat7 = {
        lives: 5,
        jumps: function thrownOutOfWindow () {
            console.log(this.lives);
        }
    };
    cat7.jumps(); // 5
    console.log(cat7); // { lives: 5, jumps: [Function: thrownOutOfWindow] }
}

catCircus();

-1

Cette rubrique est fortement liée à la bindfonction intégrée et introduite dans ECMAScript 6 Arrow Functions . C'était vraiment ennuyeux, car pour chaque nouvelle méthode de "classe" (fonction en fait) que nous voulions utiliser, nous devions le faire bindpour avoir accès à la portée.

JavaScript par défaut ne définit pas son champ d' thissur les fonctions (il ne définit pas le contexte sur this). Par défaut, vous devez indiquer explicitement le contexte que vous souhaitez avoir.

Les fonctions fléchées obtiennent automatiquement ce que l'on appelle la portée lexicale (ont accès à la définition de la variable dans son bloc conteneur). Lorsque vous utilisez des fonctions de flèche, il se lie automatiquement thisà l'endroit où la fonction de flèche a été définie en premier lieu, et le contexte de ces fonctions de flèche est son bloc conteneur.

Voyez comment cela fonctionne dans la pratique sur les exemples les plus simples ci-dessous.

Avant les fonctions flèches (pas de portée lexicale par défaut):

const programming = {
  language: "JavaScript",
  getLanguage: function() {
    return this.language;
  }
}

const globalScope = programming.getLanguage;
console.log(globalScope()); // Output: undefined

const localScope = programming.getLanguage.bind(programming);
console.log(localScope()); // Output: "JavaScript"

Avec les fonctions flèches (portée lexicale par défaut):

const programming = {
  language: "JavaScript",
  getLanguage: function() {
    return this.language;
  }
}

const arrowFunction = () => {
    console.log(programming.getLanguage());
}

arrowFunction(); // Output: "JavaScript"
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.