ES3 dans les détails

Tutoriel pour apprendre l'objet des variables en JavaScript

Nous déclarons des variables et des fonctions avec lesquelles tournent nos programmes. Mais comment, et quand l'interpréteur trouve-t-il ces données ? Que se passe-t-il quand une référence à un objet est demandée ?

14 commentaires Donner une note à l'article (5)

Article lu   fois.

L'auteur

Site personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Introduction

Beaucoup de développeurs JavaScript savent que les variables sont intimement liées au contexte d'exécution :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
var reportA = 10; // variable du contexte global

(function () {
    var reportB = 20; // variable locale d'un contexte de fonction
})();

alert(reportA); // 10
alert(reportB); // `reportB` n'est pas défini(e)

Beaucoup de développeurs savent également que la portée des variables est définie et limitée à l'exécution des contextes de fonctions. C'est-à-dire. que contrairement au C/C++, pour la structure de contrôle de boucle for par exemple, aucun contexte local n'est créé en JavaScript :

 
Sélectionnez
1.
2.
3.
4.
5.
for (var report in { reportA: 1, reportB: 2 }) {
    alert(report);
}

alert(report); // la variable `report` est toujours dans la portée même si la boucle est terminée

Regardons plus en détail ce qu'il se passe quand nous déclarons nos données.

II. Déclaration de données

Si les variables sont liées à leur contexte d'exécution, celui-ci doit savoir où leurs données sont stockées et comment y accéder. Le mécanisme permettant cela est appelé l'objet des variables.

L'objet des variables (dont la forme abrégée sera VO pour « variable object ») est un objet spécial lié à un contexte d'exécution et qui stocke :

  • les déclarations de variables (dont la forme abrégée sera VD pour « variable declaration »),
  • les déclarations de fonctions (dont la forme abrégée sera FD pour « function declaration »),
  • les paramètres formels de fonctions (dont la forme abrégée sera FP pour « formal parameters »)

déclarés dans un contexte.

À noter qu'en ES5 le concept d'objet des variables est remplacé par le modèle des environnements lexicaux.

De façon schématique dans ces exemples, il est possible de présenter l'objet des variables comme un objet JavaScript standard :

Pseudo-code
Sélectionnez
1.
VO = {}

Et comme nous l'avons dit, l'objet des variables est une propriété d'un contexte d'exécution :

Pseudo-code
Sélectionnez
1.
2.
3.
4.
5.
activeExecutionContext = {
    VO: {
        <...> // données du contexte `VD`, `FD` (et `FP`)
    }
}

Il est possible d'avoir accès à l'objet des variables du contexte global par l'intermédiaire de l'objet global (car l'objet global est lui-même l'objet des variables dans ce cas). Pour tous les autres contextes, faire référence à l'objet des variables est impossible, c'est un mécanisme du moteur.

Quand nous déclarons une variable ou une fonction dans le contexte global, ce n'est rien d'autre que la création d'une nouvelle propriété au sein de l'objet des variables avec le nom et la valeur de notre variable (ou fonction).

Exemple :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
var reportA = 10;

function precogs(minorityReport) {
    var reportB = 20;
};

precogs(30);

Avec les objets des variables correspondants :

Pseudo-code
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
// Objet des variables du contexte global
VO(globalContext) = {
    reportA: 10,
    precogs: <référence à la `FD` `precogs`>
}

// Objet des variables du contexte de la fonction `precogs`
VO(<precogs> functionContext) = {
    minorityReport: 30,
    reportB: 20
}

Voilà pour une vision théorique. Il faut juste être conscient qu'au niveau de l'implémentation réelle, l'objet des variables est quelque chose d'abstrait. Dans un contexte d'exécution réel, VO porte un autre nom et à une structure probablement différente.

III. L'objet des variables dans différents contextes d'exécution

Certaines opérations (comme l'affectation des variables) et comportements de l'objet des variables sont identiques pour toutes les déclinaisons de contexte d'exécution.

Pour expliquer cela, il va être nécessaire de présenter une partie de l'objet des variables comme commun à toutes les déclinaisons et une partie définissant des éléments et comportements additionnels.

 
Sélectionnez
1.
2.
3.
4.
5.
VO // contient des `VD` et des `FD`
║
╠══> VO(globalContext) === GO === this
║
╚══> VO(functionContext) === AO // contient des `FP` et l'`ArgO`

Voyons cela plus en détail.

III-A. L'objet des variables dans le contexte global

Tout d'abord il est nécessaire de donner une définition de l'objet global.

L'objet global (dont la forme abrégée sera GO pour « global object ») est un objet qui est déjà existant avant l'entrée dans n'importe quel contexte d'exécution, car il est créé au démarrage du programme. Cet objet existe en un unique exemplaire, et ses propriétés sont accessibles depuis n'importe quel endroit du programme. Le cycle de vie de l'objet global s'arrête quand le programme se termine.

Notons que dans un environnement navigateur hôte, chaque script (utilisé avec la balise <script> ou dans un attribut à JavaScript) a son propre contexte d'exécution global. Cela signifie que pour une page web donnée, il existe « des » contextes d'exécution globaux. Cependant, comme expliqué juste au-dessus, l'objet global est déjà existant dès qu'un script est exécuté et tous les contextes d'exécution globaux utilisent un même objet global unique. Cependant, dans ce cas, le cycle de vie de l'objet global s'arrête seulement quand tous les programmes sont terminés. Nous verrons cela plus en détail plus loin.

À sa création, l'objet global est initialisé avec des propriétés comme Math, String, Date, parseInt, etc. Il possède parmi toutes ses propriétés une propriété circulaire faisant directement référence à lui-même.

Dans le modèle objet des navigateurs, cette propriété se nomme window :

Pseudo-code
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
activeGlobalContext = {
    GO: {
        Math: <...>,
        String: <...>,
        document: <...>,
        <...>,
        window: GO
    }
}

ou encore dans Node.js, elle se nomme global :

Pseudo-code
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
activeGlobalContext = {
    GO: {
        Math: <...>,
        String: <...>,
        process: <...>,
        <...>,
        global: GO
    }
}

Cela dépend de l'implémentation.

Quand nous faisons référence à une propriété de l'objet global, nous n'utilisons aucun préfixe, juste son nom, car l'objet global n'est pas accessible. Cependant, il est possible d'en récupérer le contenu à travers sa référence circulaire à lui-même (window ou global) ou même à l'aide de la valeur this dans le contexte global. Voyons cela :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
// sans préfixe
String(10); // === `GO.String(10)` mais `GO` n'est pas accessible

// avec préfixes
window.a = 10; // === `GO.window.a = 10` === `GO.a = 10`
this.b = 20; // === `GO.b = 20`

Nous avons dit plus haut que l'objet des variables dans le contexte global est l'objet global lui-même :

Pseudo-code
Sélectionnez
1.
VO(globalContext) === GO

Il est nécessaire de bien comprendre cela, car c'est pour cette raison qu'il est possible d'accéder à une variable déclarée avec le mot-clé var en accédant à une propriété de l'objet global :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
var mr = new String('test');

alert(mr); // accès direct, elle est trouvée dans `VO(globalContext)['mr']` => `'test'`

alert(window['mr']); // accès indirect via `GO.window['mr']` === `GO['mr']` === `VO(globalContext)['mr']` => `'test'`
alert(mr === this.mr); // `true`

var mrKey = 'mr';
alert(window[mrKey]); // accès indirect avec la résolution d'identifiant dynamique de propriété => `'test'`

L'objet global ne possède que des déclarations de variables et des déclarations de fonctions, mais pas de paramètres formels.

III-B. L'objet des variables dans un contexte de fonction

En ce qui concerne les contextes d'exécution de fonctions, l'objet des variables est inaccessible ni directement ni indirectement. Il existe une équivalence de l'objet global pour le contexte de fonction qui est l'objet d'activation (dont la forme abrégée sera AO pour « activation object »).

Pseudo-code
Sélectionnez
1.
VO(functionContext) === AO

Un objet d'activation est créé en entrant dans le contexte d'une fonction et initialisé avec la propriété arguments dont la valeur est l'objet des arguments (dont la forme abrégée sera ArgO pour « arguments object ») :

Pseudo-code
Sélectionnez
1.
2.
3.
4.
5.
6.
activeFunctionContext = {
    AO: {
        <...>, // données du contexte `VD`, `FD` et `FP`
        arguments: <ArgO>
    }
}

L'objet des arguments est une propriété de l'objet d'activation. Il contient les propriétés suivantes :

  • callee — la référence à la fonction courante ;
  • length — la quantité d'arguments réellement passés ;
  • [array-index] — des nombres (convertis en chaînes de caractères) dont les valeurs sont les mêmes que celles des paramètres formels (de gauche à droite dans la liste des paramètres). La taille de [array-index] est celle de arguments.length. Les valeurs de [array-index] (arguments réellement passés) de l'objet des arguments et celle des paramètres formels (paramètres définis) sont partagées.

Exemple :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
function precogs(xReport, yReport, zReport) {

  // quantité de paramètres définis : xReport, yReport et zReport
  alert(precogs.length); // `3`

  // quantité d'arguments réellement passés : seulement xReport et yReport
  alert(arguments.length); // `2`

  // référence de la fonction à elle-même
  alert(arguments.callee === precogs); // `true`

  // paramètres partagés

  alert(xReport === arguments[0]); // `true`
  alert(xReport); // 10

  arguments[0] = 20;
  alert(xReport); // `20`

  xReport = 30;
  alert(arguments[0]); // `30`

  // cependant, pour l'argument non passé zReport,
  // le array-index de l'objet
  // des arguments n'est pas partagé

  zReport = 40;
  alert(arguments[2]); // `undefined`

  arguments[2] = 50;
  alert(zReport); // `40`

}

precogs(10, 20);

En ce qui concerne le dernier cas, dans les anciennes versions de Google Chrome (moteur V8), il y avait un bogue — où les paramètres zReport et arguments[2] étaient aussi partagés.

En ES5 le concept d'objet d'activation est également remplacé par l'unique concept des environnements lexicaux.

IV. Phases de traitement du code des contextes d'exécution

Après quelques mises au point, nous avons enfin atteint le sujet principal de ce tutoriel : le traitement du code des contextes d'exécution. Ce traitement est divisé en deux phases :

  1. Entrée dans le contexte d'exécution ;
  2. Exécution du code.

Les modifications de l'objet des variables sont intimement liées à ces deux phases.

IV-A. Entrée dans le contexte d'exécution

En entrant dans le contexte d'exécution (mais avant l'exécution du code), l'objet des variables est rempli avec les propriétés suivantes (elles ont déjà été décrites au début) :

uniquement pour les contextes de fonctions

  • pour chaque paramètre formel d'une fonction,
  • une propriété de l'objet des variables avec le nom et la valeur du paramètre formel est créée
  • et pour les arguments non passés une propriété de l'objet des variables avec le nom et la valeur undefined est créée ;

pour le contexte global et les contextes de fonctions

  • pour chaque déclaration de fonction,
  • une propriété de l'objet des variables avec le nom et la valeur de l'objet fonction est créée (si l'objet des variables contient déjà une propriété avec ce nom, sa valeur est remplacée),
  • pour chaque déclaration de variable,
  • une propriété de l'objet des variables avec le nom et la valeur undefined est créée. Si le nom de la variable est le même que celui d'un paramètre formel ou qu'une déclaration de fonction cela n'affecte pas la propriété existante.

Voyons cela avec l'exemple suivant :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
function precogs(reportA, reportB) {
    var minorityReport = 10;
    function agatha() {}
    var dashiell = function dash() {};
    (function arthur() {});
}

precogs(10); // appel

En entrant dans le contexte de la fonction precogs avec le paramètre 10, l'objet d'activation est le suivant :

Pseudo-code
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
AO(<precogs>) = {
    reportA: 10,
    reportB: undefined,
    minorityReport: undefined,
    agatha: <référence à la FD `agatha`>
    dashiell: undefined
}

Notons que cet objet d'activation ne contient pas la fonction arthur. Cela est dû au fait que arthur n'est pas une déclaration de fonction, mais une expression de fonction (dont la forme abrégée sera FE pour « function expression »). Les expressions de fonction n'affectent pas l'objet des variables.

Cependant la fonction dash est également une expression de fonction, mais comme nous le verrons plus bas, parce qu'elle est assignée à la variable dashiell, elle devient accessible via le paramètre dashiell de l'objet des variables. La différence entre une déclaration de fonction et une expression de fonction sera vue plus en détail dans le chapitre approprié.

Et maintenant, attaquons-nous à la seconde phase du traitement du code d'un contexte d'exécution — la phase d'exécution du code.

IV-B. Exécution du code

À ce stade un objet d'activation (ou l'objet global) est déjà rempli de ses propriétés (cependant, elles n'ont pas toutes leurs vraies valeurs, car la plupart ont encore la valeur undefined).

Considérez que tous les exemples fonctionnent pareil pour un objet d'activation ou l'objet global. Durant cette phase d'exécution, les valeurs sont alors modifiées comme suit :

Pseudo-code
Sélectionnez
1.
2.
AO['minorityReport'] = 10
AO['dashiell'] = <référence à la `FE` `dash`>

Rappelons encore que l'expression de fonction dash est encore en mémoire seulement parce qu'elle a été sauvée dans la déclaration de variable dashiell. Mais l'expression de fonction arthur n'est pas dans l'objet d'activation. Si nous essayons d'appeler la fonction arthur _avant ou même après sa définition, nous aurons l'erreur "arthur" n'est pas défini(e). Les fonctions d'expression qui ne sont pas sauvées dans des variables ne peuvent être appelées qu'immédiatement ou à l'intérieur d'elles-mêmes de manière récursive.

Voici un autre exemple classique :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
alert(john); // `function john() {}`

var john = 10;
alert(john); // `10`

john = 20;

function john() {}

alert(john); // `20`

Pourquoi dans la première alerte john est-elle une fonction qui est accessible avant sa déclaration ? Pourquoi n'est-ce pas 10 ou 20 ? Parce que, selon les règles, l'objet des variables est rempli avec les déclarations de fonction en entrant dans le contexte. Pendant cette phase d'entrée dans le contexte, il y a aussi une déclaration de variable john. Mais comme mentionné plus haut, cette étape est réalisée après les déclarations de fonction et les paramètres formels et cette phase n'affectent pas les propriétés existantes de même nom, que ce soit pour les déclarations de fonction ou les paramètres formels. Donc en entrant dans le contexte l'objet des variables est rempli ainsi :

Pseudo-code
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
VO = {}

VO['john'] = <référence à la `FD` `john`>

// `var john = 10;` trouvée
// si la fonction `john` n'avait pas déjà été définie
// et bien `john` aurait été `undefined`, mais dans notre cas
// la déclaration de variable n'affecte pas
// la valeur de la fonction avec le même nom

VO['john'] = <la valeur n'est pas affectée, toujours la `FD`>

Et ensuite, en entrant dans la phase d'exécution, l'objet des variables est modifié ainsi :

Pseudo-code
Sélectionnez
1.
2.
VO['john'] = 10
VO['john'] = 20

c'est ce que nous pouvons voir dans la deuxième et troisième alerte.

Dans l'exemple ci-dessous nous voyons de nouveau que les variables sont mises dans l'objet des variables pendant la phase d'entrée dans le contexte (ainsi la structure else n'est jamais exécutée, mais la variable b existe dans l'objet des variables) :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
if (true) {
    var reportA = 1;
} else {
    var reportB = 2;
}

alert(reportA); // `1`
alert(reportB); // `undefined`, mais pas « erreur : `reportB` n'est pas défini(e) »

V. Fonctionnalité des navigateurs : les contextes globaux

Comme dit plus haut, une page web n'exécute pas un Programme JavaScript, mais autant de programmes qu'elle rencontre de balises <script>, d'éléments HTMLScriptElement ou encore de code à exécuter en tant que JavaScript (attribut onclick, href="javascripst: ...", etc.). Il en résulte qu'il n'existe pas « un » contexte global, mais des contextes globaux. Cependant, tous ces contextes utilisent le même objet global.

Les phases d'entrée dans le contexte global et d'exécution du code global sont donc réitérées pour chaque nouveau programme (<script>, etc.). Mais à chaque fois, l'objet global (déjà disponible dès l'entrée dans le contexte) contient les déclarations de variables récupérées des contextes globaux précédents. Parce que les contextes globaux sont activés dans le même ordre que les programmes sont trouvés et qu'il n'existe pas de phase « d'entrée dans la page web », toute déclaration de variables venant du contexte global d'un programme qui sera exécuté plus tard n'est pas accessible dans le contexte global courant. À l'inverse, toute déclaration de variables venant du contexte global d'un programme qui a déjà été exécuté est disponible et accessible. C'est la même chose pour les déclarations de fonctions. Voyons cela avec ces exemples :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
<script>
    // Le script `echo1` sera analysé en premier

    console.log(arthur); // `function arthur() {}`
    console.log(agatha); // « error : `agatha` n'est pas défini(e) »
    console.log(dashiell); // « error : `dashiell` n'est pas défini(e) »

    function arthur() {}
</script>
<script>
    // Le script `echo2` sera analysé en second

    console.log(arthur); // `function arthur() {}`
    console.log(agatha); // `10`
    console.log(dashiell); // `function dashiell() {}`

    var agatha = 10;
    function dashiell() {}
</script>

Cela remplit notre objet global consécutivement des manières suivantes : pour le premier script

Pseudo-code
Sélectionnez
1.
2.
3.
GO(<echo1>) = {
    arthur: <référence à la FD `arthur`>
}

et pour le second script

 
Sélectionnez
1.
2.
3.
4.
5.
GO(<echo2>) = {
    arthur: <référence à la FD `arthur`>, // déjà présent dans l'objet global et trouvé d'un précédent programme
    agatha: undefined,
    dashiell: <référence à la FD `dashiell`>
}

Nous voyons donc pourquoi lors de la phase d'exécution, le premier script retourne une erreur pour agatha et dashiell qui n'existeront dans l'objet global qu'après la phase d'entrée dans le contexte du script2.

Notez également que par conséquent, de la même manière que l'ordre des instructions d'un code est important, l'ordre dans lequel les scripts sont appelés l'est aussi, car il peut changer le fonctionnement d'un programme.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
<script>
    // Ce script `echo2` sera analysé en premier

    console.log(arthur); // « error : `arthur` n'est pas défini(e) »
    console.log(agatha); // `10`
    console.log(dashiell); // `function dashiell() {}`

    var agatha = 10;
    function dashiell() {}
</script>
<script>
    // Ce script `echo1` sera analysé en second

    console.log(arthur); // `function arthur() {}`
    console.log(agatha); // `10`
    console.log(dashiell); // `function dashiell() {}`

    function arthur() {}
</script>

à cause de l'état de l'objet global évoluant ainsi :

Pseudo-code
Sélectionnez
1.
2.
3.
4.
GO(<echo2>) = {
    agatha: 10,
    dashiell: <référence à la FD `dashiell`>
}

et

 
Sélectionnez
1.
2.
3.
4.
5.
GO(<echo1>) = {
    agatha: 10, // déjà présent dans l'objet global et trouvé d'un précédent programme
    dashiell: <référence à la FD `dashiell`>  // déjà présent dans l'objet global et trouvé d'un précédent programme
    arthur: <référence à la FD `arthur`>
}

VI. À propos des variables

On voit souvent dans différents articles (et même livres) sur le JavaScript l'affirmation suivante : « il est possible de déclarer une variable globale en utilisant le mot-clé var (dans le contexte global) et sans le mot-clé var (depuis n'importe quel contexte) ». Ce n'est pas exactement ça. Soyez assuré de cela :

les variables se déclarent uniquement avec le mot-clé var.

Et des affectations comme ci-dessous :

 
Sélectionnez
1.
reportA = 10;

créent simplement une nouvelle propriété dans l'objet global, mais pas une variable. « Pas une variable », mais pas dans le sens qu'elle ne pourra pas être changée lors de la phase d'exécution (on pourra y accéder, car VO(globalContext) === GO), mais « pas une variable » dans le sens qu'elle n'est pas dans l'objet des variables lors de la phase d'entrée.

Regardons cet exemple pour tester la différence :

 
Sélectionnez
1.
2.
3.
4.
5.
alert(reportA); // `undefined`
alert(reportB); // « erreur, `reportB` n'est pas défini(e) »

reportB = 10;
var reportA = 20;

La différence vient de l'objet des variables et des phases où il est modifié (phase d'entrée dans le contexte et phase d'exécution de code) :

Pour l'entrée dans le contexte :

Pseudo-code
Sélectionnez
1.
2.
3.
VO = {
    reportA: undefined
}

Nous voyons qu'il n'existe aucune variable reportB. reportB n'apparaîtra que lors de la phase d'exécution du code (et dans notre cas reportB n'apparaîtra pas, car il va y avoir une erreur).

Changeons le code :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
alert(reportA); // `undefined`, nous savons pourquoi

reportB = 10;
alert(reportB); // `10`, créée lors de l'exécution du code

var reportA = 20;
alert(reportA); // `20`, modifiée lors de l'exécution du code

Voici le point important en ce qui concerne les variables. Les variables, par opposition aux simples propriétés, ont un attribut {DontDelete}, ce qui signifie qu'il est impossible de les supprimer avec l'opérateur delete :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
reportA = 10;
alert(window.reportA); // `10`

alert(delete reportA); // `true`

alert(window.reportA); // `undefined`

var reportB = 20;
alert(window.reportB); // `20`

alert(delete reportB); // `false`

alert(window.reportB); // toujours `20`

Notons qu'en ES5 {DontDelete} a été renommé en [[Configurable]] et peut être manuellement géré via l'utilisation de la méthode Object.defineProperty.

Cependant, il y a un contexte d'exécution où cette règle n'a pas d'effet. C'est le contexte eval : l'attribut {DontDelete} n'est pas appliqué pour les variables :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
eval('var minorityReport = 10;');
alert(window.minorityReport); // `10`

alert(delete minorityReport); // `true`

alert(window.minorityReport); // `undefined`

Si en essayant votre code dans une console JavaScript, vous pouvez supprimer une variable, c'est que cette console utilise eval pour évaluer votre code.

VII. Fonctionnalité des moteurs : la propriété __parent__

Comme nous l'avons déjà mentionné, conformément au standard, accéder directement à l'objet d'activation est impossible. Cependant, dans plusieurs moteurs comme celui de Mozilla Firefox (SpiderMonkey) ou Rhino les fonctions ont une propriété spéciale __parent__ qui est une référence à l'objet d'activation (ou à l'objet global) dans lequel ces fonctions ont été créées.

Exemple (SpiderMonkey et Rhino) :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
var GO = this;
var minorityReport = 10;

function agatha() {}

alert(agatha.__parent__); // `GO`

var VO = agatha.__parent__;

alert(VO.minorityReport); // `10`
alert(VO === GO); // `true`

Dans l'exemple ci-dessus, nous voyons que agatha est créée dans le contexte global et sa propriété __parent__ est ajoutée à l'objet des variables du contexte global, c.-à-d. à l'objet global.

Cependant obtenir l'objet d'activation dans SpiderMonkey de la même manière n'est pas possible : cela dépendra de la version, mais __parent__ pour des fonctions dans des fonctions retournera null ou l'objet global.

Dans Rhino, l'accès à l'objet d'activation est permis et disponible de cette manière :

Exemple (Rhino) :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
var GO = this;
var reportA = 10;

(function dashiell() {

    var reportB = 20;

    // l'objet d'activation du contexte `dashiell`
    var AO = (function () {}).__parent__;

    print(AO.reportB); // 20

    // __parent__ de l'objet d'activation
    // courant est déjà l'objet global,
    // c.-à-d. qu'une chaîne spéciale d'objets des variables est formée,
    // on la nomme : chaîne des portées
    print(AO.__parent__ === GO); // `true`

    print(AO.__parent__.reportA); // `10`

})();

VIII. Conclusion

Dans ce tutoriel, nous avons vu plus en détail l'étude des objets relatifs aux contextes d'exécution. Les prochains chapitres seront consacrés à la résolution des identifiants, aux chaînes des portées et, par conséquent, aux fermetures en JavaScript.

IX. Remerciements

Nous remercions Bruno Lesieur qui nous a autorisés à publier ce tutoriel.

Nous remercions également Laethy pour la mise au gabarit et Claude Leloup pour la correction orthographique.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2018 Nom Auteur. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.