Maison > Article > interface Web > Série JavaScript Advanced : portée et espace de noms
Variables globales implicites
Variables locales
Levage de déclaration de variable (Hoisting)
Ordre de résolution de nom
Espace de noms
Conclusion
Bien que JavaScript prenne en charge les extraits de code créés par une paire d'accolades, il ne prend pas en charge la portée au niveau du bloc ; seule la portée de la fonction est prise en charge.
function test() { // 一个作用域 for(var i = 0; i < 10; i++) { // 不是一个作用域 // count } console.log(i); // 10 }
Note du traducteur : si le crochet gauche de l'objet return et return ne sont pas sur la même ligne, une erreur se produira.
(Remarque : s'il ne se trouve pas dans une instruction d'affectation, mais dans une expression de retour ou un paramètre de fonction, {...} sera analysé comme un segment de code, et non comme une analyse syntaxique littérale de l'objet . Si l'insertion automatique d'un point-virgule est prise en compte, cela peut conduire à des erreurs subtiles)
// 译者注:下面输出 undefined function add(a, b) { return a + b; } console.log(add(1, 2));
Il n'y a pas de définition explicite d'espace de noms en JavaScript, ce qui signifie que tous les objets sont définis sous. un espace de noms partagé à l’échelle mondiale.
Chaque fois qu'une variable est référencée, JavaScript parcourra toute la portée vers le haut jusqu'à ce qu'il trouve la variable. Si la portée globale est atteinte mais que la variable n'est toujours pas trouvée, une exception ReferenceError est levée.
Variables globales implicites
// 脚本 A foo = '42'; // 脚本 B var foo = '42'
Les deux scripts ci-dessus ont des effets différents. Le script A définit la variable foo dans la portée globale, tandis que le script B définit la variable foo dans la portée actuelle.
Encore une fois, l'effet ci-dessus est complètement différent. Déclarer des variables sans utiliser var entraînera la création de variables globales implicites.
// 全局作用域 var foo = 42; function test() { // 局部作用域 foo = 21; } test(); foo; // 21
Déclarer la variable foo sans utiliser le mot-clé var dans le test de fonction écrasera la variable externe du même nom. Cela peut ne pas sembler être un gros problème au début, mais lorsque vous avez des milliers de lignes de code, déclarer des variables sans utiliser var peut conduire à des bugs difficiles à détecter.
// 全局作用域 var items = [/* 数组 */]; for(var i = 0; i < 10; i++) { subLoop(); } function subLoop() { // subLoop 函数作用域 for(i = 0; i < 10; i++) { // 没有使用 var 声明变量 // 干活 } }
La boucle externe se terminera après le premier appel à subLoop car subLoop écrase la variable globale i. Cette erreur peut être évitée en déclarant la variable en utilisant var dans la deuxième boucle for. N'omettez jamais le mot-clé var lors de la déclaration d'une variable, sauf s'il s'agit du comportement souhaité affectant la portée externe.
Variables locales
Les variables locales en JavaScript ne peuvent être déclarées que de deux manières, l'une en tant que paramètre de fonction, l'autre est déclarée via le mot-clé var.
// 全局变量 var foo = 1; var bar = 2; var i = 2; function test(i) { // 函数 test 内的局部作用域 i = 5; var foo = 3; bar = 4; } test(10);
foo et i sont des variables locales dans la fonction test, et l'affectation à bar écrasera la variable du même nom dans la portée globale.
Histage des déclarations de variables (Hoisting)
JavaScript lèvera les déclarations de variables. Cela signifie que les expressions var et les déclarations de fonction seront hissées en haut de la portée actuelle.
bar(); var bar = function() {}; var someValue = 42; test(); function test(data) { if (false) { goo = 1; } else { var goo = 2; } for(var i = 0; i < 100; i++) { var e = data[i]; } }
Le code ci-dessus sera converti avant son exécution. JavaScript hissera les expressions var et les déclarations de fonctions en haut de la portée actuelle.
// var 表达式被移动到这里 var bar, someValue; // 缺省值是 'undefined' // 函数声明也会提升 function test(data) { var goo, i, e; // 没有块级作用域,这些变量被移动到函数顶部 if (false) { goo = 1; } else { goo = 2; } for(i = 0; i < 100; i++) { e = data[i]; } } bar(); // 出错:TypeError,因为 bar 依然是 'undefined' someValue = 42; // 赋值语句不会被提升规则(hoisting)影响 bar = function() {}; test();
Ne pas avoir de portée de bloc entraîne non seulement le déplacement des expressions var de l'intérieur de la boucle vers l'extérieur, mais rend également certaines expressions if plus difficiles à lire.
Dans le code original, l'expression if semble modifier la variable globale goo, mais en fait elle modifie la variable locale après l'application de la règle de promotion.
Sans connaissance du levage, le code suivant semble lever une exception ReferenceError.
// 检查 SomeImportantThing 是否已经被初始化 if (!SomeImportantThing) { var SomeImportantThing = {}; }
En fait, le code ci-dessus fonctionne bien car l'expression var est hissée au sommet de la portée globale.
var SomeImportantThing; // 其它一些代码,可能会初始化 SomeImportantThing,也可能不会 // 检查是否已经被初始化 if (!SomeImportantThing) { SomeImportantThing = {}; }
Note du traducteur : il existe un article présentant le levage sur le site Web de Nettuts, et le code qu'il contient est très instructif.
// 译者注:来自 Nettuts+ 的一段代码,生动的阐述了 JavaScript 中变量声明提升规则 var myvar = 'my value'; (function() { alert(myvar); // undefined var myvar = 'local value'; })();
Ordre de résolution des noms
Toutes les étendues en JavaScript, y compris la portée globale, ont un nom spécial qui pointe vers l'objet actuel. Il existe également une variable par défaut arguments dans la portée de la fonction, qui contient les paramètres transmis à la fonction. Par exemple, lors de l'accès à la variable foo dans une fonction, JavaScript recherchera dans l'ordre suivant :
S'il existe une définition de var foo dans la portée actuelle.
Si les paramètres formels de la fonction utilisent le nom foo.
Si la fonction elle-même s'appelle foo.
Retournez à la portée précédente et recommencez à partir du n°1.
Espace de noms
Une erreur courante causée par le fait de n'avoir qu'une seule portée globale est les conflits de noms. En JavaScript, cela peut être facilement résolu avec des wrappers anonymes.
(Remarque : les paramètres d'arguments personnalisés empêcheront la création d'objets d'arguments natifs.)
(function() { // 函数创建一个命名空间 window.foo = function() { // 对外公开的函数,创建了闭包 }; })(); // 立即执行此匿名函数
Les fonctions anonymes sont considérées comme des expressions ; par conséquent, pour l'appel, elles doivent d'abord être exécutées.
( // 小括号内的函数首先被执行 function() {} ) // 并且返回函数对象 () // 调用上面的执行结果,也就是函数对象
Il existe d'autres façons d'appeler des expressions de fonction. Par exemple, les deux méthodes suivantes ont une syntaxe différente, mais l'effet est exactement le même.
// 另外两种方式 +function(){}(); (function(){}());
Conclusion
Il est recommandé d'utiliser des wrappers anonymes (Note du traducteur : fonctions anonymes auto-exécutables) pour créer des espaces de noms. Cela évite non seulement les conflits de noms, mais facilite également la modularisation du programme.
De plus, l'utilisation de variables globales est considérée comme une mauvaise pratique. Un tel code est sujet aux erreurs et coûteux à maintenir.
Ce qui précède est le contenu de la série avancée JavaScript - portée et espace de noms. Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois (www.php.cn) !