2008-10-24 15 views
12

Aujourd'hui, j'ai eu une discussion avec un collègue sur les fonctions imbriquées en Javascript:Quelle est la portée d'une fonction dans Javascript/ECMAScript?

function a() { 
    function b() { 
     alert('boo') 
    } 
    var c = 'Bound to local call object.' 
    d = 'Bound to global object.' 
} 

Dans cet exemple, les essais souligner que b n'est pas accessible en dehors du corps d'un, tout comme c est. Cependant, d est - après l'exécution d'un(). Vous cherchez la définition exacte de ce comportement dans le ECMAScript v.3 standard, je n'ai pas trouvé le libellé exact que je cherchais; ce que ne dit pas la Sec.13 p.71, est l'objet auquel l'objet fonction créé par l'instruction de déclaration de fonction doit être lié. Est-ce que je manque quelque chose?

Répondre

21

C'est portée statique. Les instructions d'une fonction sont définies dans cette fonction.

Javascript a un comportement bizarre, mais, ce qui est que sans le mot-clé var, vous avez impliqué une variable globale . C'est ce que vous voyez dans votre test. Votre variable "d" est disponible car elle est implicite globale, bien qu'elle soit écrite dans le corps d'une fonction.

Aussi, pour répondre à la deuxième partie de votre question: Une fonction existe dans n'importe quelle portée, comme une variable.

Sidenote: Vous ne voulez probablement pas de variables globales, en particulier pas celles implicites. Il est recommandé de toujours utiliser le mot-clé var, afin d'éviter toute confusion et de garder tout propre.

Sidenote: La norme ECMA est probablement pas l'endroit le plus utile de trouver des réponses sur Javascript, bien qu'il ne soit certainement pas une mauvaise ressource. Rappelez-vous que javascript dans votre navigateur est juste une implémentation de cette norme, donc le document de normes vous donnera les règles qui ont été (la plupart du temps) suivies par les implémenteurs lors de la construction du moteur javascript. Il ne peut pas offrir d'informations spécifiques sur les implémentations qui vous intéressent, à savoir les principaux navigateurs. Il y a quelques livres en particulier qui vous donneront des informations très directes sur le comportement des implémentations javascript dans les principaux navigateurs. Pour illustrer la différence, je vais inclure des extraits ci-dessous à la fois de la spécification ECMAScript, et un livre sur Javascript. Je pense que vous serez d'accord que le livre donne une réponse plus directe.

est ici de la ECMAScript Language Specification:

10,2 Saisie d'un contexte d'exécution

Chaque fonction et constructeur appel entre dans un nouveau contexte d'exécution, même si une fonction est elle-même appelle récursivement. Chaque retour quitte un contexte d'exécution . Une exception lancée, si elle n'est pas interceptée, peut également quitter un ou plusieurs contextes d'exécution.

Lorsque le contrôle pénètre dans un contexte d'exécution, la portée chaîne est créé et initialisé, la variable instanciation est effectuée, et cette valeur est déterminée.

L'initialisation de la chaîne de portée, instanciation variable et la détermination de la cette valeur dépend du type de code étant entré.

est ici de O'Reilly Javascript: The Definitive Guide (5th Edition):

8.8.1 lexicale

Fonctions JavaScript sont lexicalement plutôt que de portée dynamique. Ce signifie qu'ils s'exécutent dans la portée dans qu'ils sont définis, pas la portée à partir de laquelle ils sont exécutés. Lorsqu'une fonction est définie, la chaîne de portée actuelle est enregistrée et devient une partie de l'état interne de la fonction. ...

Hautement recommandé pour couvrir ce genre de questions est le livre de Douglas Crockford:

JavaScript, The Good Parts http://oreilly.com/catalog/covers/9780596517748_cat.gif

Javascript, The Good Parts, également de O'Reilly.

+2

Exactement le droit - en gros 'la fonction a() {}' est équivalente à 'var a = function() {}' (il y a quelques différences sémantiques mineures, mais rien de trop significatif). – olliej

+0

merci, mais où puis-je trouver les assertions suivantes dans la norme ECMAScript (ou est-il manquant?): "Les instructions au sein d'une fonction sont étendues dans cette fonction." Dans mon impression, la sémantique de "var a = function() {}" sont bien définies, mais pas celles de l'instruction "function a() {...}". –

+0

Le standard ECMAScript ne vous donnera que les instructions pour l'implémentation d'ECMAScript, dont Javascript n'est qu'un membre de la famille. Donc, vous ne trouverez pas cette déclaration exacte, mais il y a d'autres ressources qui peuvent vous aider. Voir ma note supplémentaire ci-dessus. – keparo

4

Si je comprends bien, ceux-ci sont équivalentes en ce qui concerne portée:

function a() { ... } 

et

var a = function() { ... } 
0

...

function a() { 
    function b() { 
     alert('boo') 
    } 
    var c = 'Bound to local call object.' 
    d = 'Bound to global object.' 
} 

sans être précédé par var, d est global. Pour ce faire, à fait d privé:

function a() { 
    function b() { 
     alert('boo') 
    } 
    var c = 'Bound to local call object.' 
    var d = 'Bound to local object.' 
} 
2

Il semble important de noter que, si d est en cours de création en tant que « global », il est en réalité en cours de création comme une propriété de l'objet de la fenêtre. Cela signifie que vous risquez d'écraser par inadvertance quelque chose qui existe déjà sur l'objet window ou que votre variable ne pourra pas être créée du tout. Alors:

function a() { 
    d = 'Hello World'; 
} 
alert(window.d); // shows 'Hello World' 

Mais vous ne pouvez pas faire:

function a() { 
    document = 'something'; 
} 

parce que vous ne pouvez pas écraser l'objet window.document.

À toutes fins utiles, vous pouvez imaginer que tout votre code fonctionne dans un bloc géant with(window).

+0

Oui, ce comportement est spécifié dans Sec. 10.1.9 de la norme ECMAScript. –

1

Javascript a deux champs d'application. Global et fonctionnel. Si vous déclarez une variable à l'intérieur d'une fonction en utilisant le mot clé "var", elle sera locale à cette fonction et à toutes les fonctions internes. Si vous déclarez une variable en dehors d'une fonction, elle a une portée globale.

Enfin, si vous omettez le mot-clé var lors de la première déclaration d'une variable, javascript suppose que vous vouliez une variable globale, peu importe où vous le déclarez. Donc, vous appelez la fonction a, et la fonction a déclare une variable globale d.

Questions connexes