Pourquoi l'argument de fonction n'est-il pas écrasé lors de la création de variable du même nom à l'intérieur de la fonction?

var a = 'why is this not undefined?';
function checkScope(a) {
    var a;
    console.log(a);
}
checkScope(a);

Javascript est un langage de portée fonctionnelle, non? Quand je déclare une nouvelle variable juste à l'intérieur de la fonction qui utilise le même nom que l'argument fonctionnel, pourquoi la variable nouvellement définie détient toujours les mêmes données que l'argument?

j'ai pensé qu'il devrait être indéfini?

21
demandé sur yochannah 2015-01-15 15:14:55

4 réponses

var a; est en fait une variable déclaration déclaration. Lorsque la fonction est définie, toutes les variables qui y sont déclarées sont traitées avant l'exécution du code et vous pouvez donc utiliser les variables avant même que la ligne de déclaration soit exécutée à l'exécution. Ceci est appelé var levage. Donc, peu importe combien de fois vous déclarez une variable, la variable est en fait déclaré qu'une seule fois.

Dans votre cas, vous avez défini a comme l'un des paramètres de la fonction, qui est portée à la fonction en cours. Et puis vous déclarez une variable avec le même nom. Depuis a est déjà déclarée dans la fonction, comme l'un des paramètres, le var a; déclaration sera ignoré.

C'est pourquoi vous obtenez why is this not undefined? dans la console.

au Lieu de var a;, disons que vous aviez var a = 1;, dans ce cas, la variable est déjà déclarée, mais l'expression assignment sera évalué au moment de l'exécution et la valeur 1 sera attribué à a. Ainsi, le console.log print 1.


ce comportement est expliqué dans la spécification ECMA Script 5.1, sous la section 10.5 Déclaration De Liaison De L'Instanciation,

  1. Si code est le code de la fonction, puis

    A. Que func soit la fonction dont la méthode interne [[Call]] initiée l'exécution de code. Laissez noms la valeur de func ’s [[FormalParameters]] propriété interne.

    b. Laissez argCount soit le nombre d'éléments dans args.

    c. Laissez n le nombre 0.

    D. Pour chaque chaîne argNamenoms, dans l'ordre des listes faites

    j'. Laissez n être la valeur actuelle n plus de 1.

    ii. Si n est supérieur à argCount, laissez - v ne pas faire v la valeur de l' n’élément th args.

    iii. Let argAlreadyDeclared être le résultat de l'appel à env’s HasBinding méthode concrète en passant argName comme la argument.

    iv. Si argAlreadyDeclared false, appeler env ’s Createmutable-Reliing concrete method passing argName comme la argument.

    v. Appeler env ’s Setmutable Binding concrete method passing argName, v et strict comme arguments.

....

  1. Pour chaque VariableDeclaration et variable Declarationoin d code, dans l'ordre du texte source do

    un. Laissez dnidentificateur d.

    b. Laissez varAlreadyDeclared être le résultat de l'appel à envde la méthode de bétonnage dn comme argument.

    c. Si varAlreadyDeclared false, alors

    I. Appel env ’s Createmutable-Reliing concrete method passing dn et reliures configurables comme arguments.

    ii. Appeler env ’s Setmutable Binding concrete method passing dn, Non défini, et strict comme arguments.

comme nous le voyons dans la spécification, les arguments et les variables déclarées dans la fonction, Tous sont en fait définis dans l'environnement d'exécution correspondant à la fonction dans laquelle ils sont définis. Ainsi, si les arguments et les variables ont le même nom, la variable n'est en fait définie qu'une seule fois et la seconde déclaration est ignorée.

41
répondu thefourtheye 2015-01-17 19:35:27

le paramètre est encore défini à l'intérieur de la fonction, becase le var a; est ignoré lorsque la variable est déjà définie dans la même portée.

déclaration var a; ne signifie pas que la variable est créée à ce point dans le code. Toutes les déclarations de variables sont hissé vers le haut de la portée, de sorte que vous pouvez les re-écl arer autant de fois que vous voulez dans la portée, et ils sont toujours créés une seule fois.

Si une déclaration a une affectation si, comme var a = 2;, la cession se produit lorsque la déclaration est dans le code, que la déclaration soit ignorée ou non.

Exemple:

function check(a) {
  // both a and b exist here
  document.write('a = ' + a + ', b = ' + b + '<br>');
  var b = 1;
  document.write('a = ' + a + ', b = ' + b + '<br>');
  var a = 2; // not recreated, but assigned
  document.write('a = ' + a + ', b = ' + b + '<br>');
}

check(42);
4
répondu Guffa 2015-01-15 12:25:06
  1. vous passez la variable a à la fonction check comme paramètre.function checkScope(a) {

  2. à l'intérieur de la fonction, vous êtes à nouveau en essayant de déclarer var a, var a;

les Deux sont dans la même portée, non? j'.e à la fois à l'intérieur de la fonction check();

Et après docs, qui var a à l'intérieur de la fonction est la même variable que vous avez passée en paramètre et vous l'utilisez juste avant déclaration... vous pouvez le faire en JS

donc le code que vous avez écrit est équivalent à

var a = 'why is this not undefined?';
function checkScope(a) {

    console.log(a);
}
checkScope(a);

I. e la var a est simplement ignorée.

Et ce que vous vous attendez à ce que la var doit renvoyer undefined alors le code sera comme ceci

var a = 'why is this not undefined?';
function checkScope() {
   var a
    console.log(a);
}
checkScope();

cette fois nous ne passons pas le paramètre a à la fonction et une nouvelle variable var a est créé dans le cadre de la fonction scope, devient donc indéfini

4
répondu Naeem Shaikh 2015-01-15 12:28:50

parce que JavaScript ignore les redeclarations des variables. Toutefois, si vous avez eu ceci à la place:

var a = 'why is this not undefined?';
function checkScope(a) {
    var a = 'foo';
    console.log(a);
}
checkScope(a);

La valeur a serait écrasé. Parce que var a = 'foo'; est composé d'une déclaration variable (var a;) et une assignation de valeur (a = 'foo';);

Ce comportement est décrit dans la MDN docs.

2
répondu Danilo Valente 2015-01-15 12:22:13