Une introduction à la portée en JavaScript

La portée définit la durée de vie et la visibilité d'une variable. Les variables ne sont pas visibles en dehors de la portée dans laquelle elles sont déclarées.

JavaScript a une portée de module, une portée de fonction, une portée de bloc, une portée lexicale et une portée globale.

Portée mondiale

Les variables définies en dehors de toute fonction, bloc ou portée de module ont une portée globale. Les variables de portée globale sont accessibles de partout dans l'application.

Lorsqu'un système de modules est activé, il est plus difficile de créer des variables globales, mais on peut toujours le faire. En définissant une variable en HTML, en dehors de toute fonction, une variable globale peut être créée:

 let GLOBAL_DATA = { value : 1};  console.log(GLOBAL_DATA);

Lorsqu'il n'y a pas de système de modules en place, il est beaucoup plus facile de créer des variables globales. Une variable déclarée en dehors de toute fonction, dans n'importe quel fichier, est une variable globale.

Les variables globales sont disponibles pour la durée de vie de l'application.

Une autre façon de créer une variable globale consiste à utiliser l' windowobjet global n'importe où dans l'application:

window.GLOBAL_DATA = { value: 1 };

À ce stade, la GLOBAL_DATAvariable est visible partout.

console.log(GLOBAL_DATA)

Comme vous pouvez l'imaginer, ces pratiques sont de mauvaises pratiques.

Portée du module

Avant les modules, une variable déclarée en dehors de toute fonction était une variable globale. Dans les modules, une variable déclarée en dehors de toute fonction est masquée et n'est pas disponible pour les autres modules sauf si elle est explicitement exportée.

L'exportation rend une fonction ou un objet disponible pour d'autres modules. Dans l'exemple suivant, j'exporte une fonction à partir du sequence.jsfichier du module:

// in sequence.js export { sequence, toList, take };

L'importation rend une fonction ou un objet, à partir d'autres modules, disponible pour le module actuel.

import { sequence, toList, toList } from "./sequence";

D'une certaine manière, nous pouvons imaginer un module comme une fonction auto-exécutable qui prend les données d'importation comme entrées et renvoie les données d'exportation.

Portée de la fonction

La portée de la fonction signifie que les paramètres et les variables définis dans une fonction sont visibles partout dans la fonction, mais ne sont pas visibles en dehors de la fonction.

Considérez la fonction suivante qui s'exécute automatiquement, appelée IIFE.

(function autoexecute() { let x = 1; })(); console.log(x); //Uncaught ReferenceError: x is not defined

IIFE signifie expression de fonction immédiatement invoquée et est une fonction qui s'exécute immédiatement après sa définition.

Les variables déclarées avec varn'ont qu'une portée de fonction. De plus, les variables déclarées avec varsont hissées au sommet de leur portée. De cette façon, ils peuvent être consultés avant d'être déclarés. Jetez un œil au code ci-dessous:

function doSomething(){ console.log(x); var x = 1; } doSomething(); //undefined

Cela n'arrive pas pour let. Une variable déclarée avec letn'est accessible qu'après sa définition.

function doSomething(){ console.log(x); let x = 1; } doSomething(); //Uncaught ReferenceError: x is not defined

Une variable déclarée avec varpeut être re-déclarée plusieurs fois dans la même portée. Le code suivant est très bien:

function doSomething(){ var x = 1 var x = 2; console.log(x); } doSomething();

Les variables déclarées avec letou constne peuvent pas être re-déclarées dans la même portée:

function doSomething(){ let x = 1 let x = 2; } //Uncaught SyntaxError: Identifier 'x' has already been declared

Peut-être que nous n'avons même pas à nous en soucier, car cela vara commencé à devenir obsolète.

Portée du bloc

La portée du bloc est définie avec des accolades. Il est séparé par {et }.

Les variables déclarées avec letet constpeuvent avoir une portée de bloc. Ils ne sont accessibles que dans le bloc dans lequel ils sont définis.

Considérez le code suivant qui met l'accent sur la letportée du bloc:

let x = 1; { let x = 2; } console.log(x); //1

En revanche, la vardéclaration n'a pas de portée de bloc:

var x = 1; { var x = 2; } console.log(x); //2

Un autre problème courant lié à l'absence de portée de bloc est l'utilisation d'une opération asynchrone comme setTimeout()dans une boucle. Le code de boucle qui coule affiche le nombre 5, cinq fois.

(function run(){ for(var i=0; i<5; i++){ setTimeout(function logValue(){ console.log(i); //5 }, 100); } })();

L' forinstruction de boucle, avec la letdéclaration, crée une nouvelle variable locale dans la portée du bloc, pour chaque itération. Le code de boucle suivant s'affiche 0 1 2 3 4 5.

(function run(){ for(let i=0; i<5; i++){ setTimeout(function log(){ console.log(i); //0 1 2 3 4 }, 100); } })();

Portée lexicale

La portée lexicale est la capacité de la fonction interne d'accéder à la portée externe dans laquelle elle est définie.

Considérez le code suivant:

(function autorun(){ let x = 1; function log(){ console.log(x); }; function run(fn){ let x = 100; fn(); } run(log);//1 })();

La logfonction est une fermeture. Il fait référence à la xvariable à partir de sa fonction parente autorun(), pas à celle de la run()fonction.

La fonction de fermeture a accès à la portée dans laquelle elle a été créée, pas à la portée dans laquelle elle a été exécutée.

La portée de la fonction locale de autorun()est la portée lexicale de la log()fonction.

Chaîne de portée

Every scope has a link to the parent scope. When a variable is used, JavaScript looks down the scope chain until it either finds the requested variable or until it reaches the global scope, which is the end of the scope chain.

Look at the next example:

let x0 = 0; (function autorun1(){ let x1 = 1; (function autorun2(){ let x2 = 2; (function autorun3(){ let x3 = 3; console.log(x0 + " " + x1 + " " + x2 + " " + x3);//0 1 2 3 })(); })(); })();

The autorun3() inner function has access to the local x3 variable. It has also access to the x1 and x2 variables from the outer functions and the x0 global variable.

If it cannot find the variable, it will return an error in strict mode.

"use strict"; x = 1; console.log(x) //Uncaught ReferenceError: x is not defined

In non-strict mode, referred to as “sloppy mode”, it will do a bad thing and create a global variable.

x = 1; console.log(x); //1

Conclusion

Variables defined in global scope are available everywhere in the application.

In a module, a variable declared outside any function is hidden and not available to other modules unless it is explicitly exported.

Function scope means that parameters and variables defined in a function are visible everywhere within the function

Variables declared with let and const have block scope. var doesn’t have block scope.

Discover Functional JavaScript was named one of thebest new Functional Programming books by BookAuthority!

For more on applying functional programming techniques in React take a look atFunctional React.

Learn functional React, in a project-based way, with Functional Architecture with React and Redux.

Follow on Twitter