web-dev-qa-db-fra.com

Ordre des fonctions JavaScript: pourquoi est-ce important?

Question originale:

JSHint se plaint lorsque mon JavaScript appelle une fonction qui est définie plus bas dans la page que son appel. Cependant, ma page est pour un jeu et aucune fonction n'est appelée tant que tout n'est pas téléchargé. Alors, pourquoi les fonctions d'ordre apparaissent-elles dans mon code?

EDIT: Je pense avoir trouvé la réponse.

http://www.qualmentgood.com/2010/2/JavaScript-Scoping-and-Hoisting

Je gémis à l'intérieur. On dirait que je dois passer un autre jour à réorganiser six mille lignes de code. La courbe d'apprentissage avec javascript n'est pas raide du tout, mais c'est très loooooong.

100
Chris Tolworthy

tl; dr Si vous n'appelez rien jusqu'à ce que tout soit chargé, tout devrait bien se passer.


Edit: Pour un aperçu qui couvre également certaines déclarations ES6 (let, const): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Référence/Scope_Cheatsheet

Ce comportement étrange dépend de

  1. Comment vous définissez les fonctions et
  2. Quand vous les appelez.

Voici quelques exemples.

bar(); //This won't throw an error
function bar() {}

foo(); //This will throw an error
var foo = function() {}
bar();
function bar() {
    foo(); //This will throw an error
}
var foo = function() {}
bar();
function bar() {
    foo(); //This _won't_ throw an error
}
function foo() {}
function bar() {
    foo(); //no error
}
var foo = function() {}
bar();

Ceci est dû à quelque chose appelé hissage !

Il existe deux façons de définir des fonctions: Fonction déclaration et fonction expression. La différence est ennuyeuse et minute, alors disons simplement cette chose un peu fausse: si vous l'écrivez comme function name() {}, c'est une déclaration , et quand vous l'écrivez comme var name = function() {} (ou une fonction anonyme affectée à un retour, etc.), c'est une expression de fonction .

Voyons d’abord comment les variables sont gérées:

var foo = 42;

//the interpreter turns it into this:
var foo;
foo = 42;

Maintenant, comment la fonction déclarations est gérée:

var foo = 42;
function bar() {}

//turns into
var foo; //Insanity! It's now at the top
function bar() {}
foo = 42;

Les instructions var "jettent" le création de foo tout en haut, mais ne lui attribuent pas encore la valeur. La déclaration de fonction vient ensuite dans la ligne, et finalement une valeur est assignée à foo.

Et qu'en est-il?

bar();
var foo = 42;
function bar() {}
//=>
var foo;
function bar() {}
bar();
foo = 42;

Seul le déclaration de foo est déplacé vers le haut. Cette affectation intervient uniquement après que l'appel à bar a été effectué, là où il se trouvait avant tout le levage.

Et enfin, pour la concision:

bar();
function bar() {}
//turns to
function bar() {}
bar();

Maintenant, qu'en est-il de la fonction expressions?

var foo = function() {}
foo();
//=>
var foo;
foo = function() {}
foo();

Tout comme les variables régulières, foo est d’abord déclaré au point le plus élevé de la portée, puis une valeur lui est attribuée.

Voyons pourquoi le deuxième exemple génère une erreur.

bar();
function bar() {
    foo();
}
var foo = function() {}
//=>
var foo;
function bar() {
    foo();
}
bar();
foo = function() {}

Comme nous l'avons vu précédemment, seule la création de foo est hissée, l'assignation vient là où elle apparaissait dans le code "original" (non hissé). Lorsque bar est appelé, c'est avant que foo ne se voit attribuer une valeur, donc foo === undefined. Maintenant, dans le corps de fonction de bar, c'est comme si vous exécutiez undefined(), ce qui génère une erreur.

278
Zirak

La raison principale est probablement que JSLint ne fait qu'une seule passe sur le fichier, il ne vous connaît donc pas va définir une telle fonction.

Si vous avez utilisé la syntaxe d'instruction de fonctions

function foo(){ ... }

Il n'y a en réalité aucune différence du tout lorsque vous déclarez la fonction (elle se comporte toujours comme si la déclaration se trouvait au début).

D'autre part, si votre fonction a été définie comme une variable régulière

var foo = function() { ... };

Vous devez vous assurer de ne pas l'appeler avant l'initialisation (cela peut en fait être une source de bogues).


Étant donné que la réorganisation de tonnes de code est compliquée et peut être une source de bogues, je vous suggère de rechercher une solution de contournement. Je suis presque sûr que vous pouvez donner à JSLint le nom de variables globales à l'avance pour ne pas se plaindre de contenu non déclaré.

Mettre un commentaire sur le début du fichier

/*globals foo1 foo2 foo3*/

Ou vous pouvez utiliser une zone de texte pour cela. (Je pense aussi que vous pouvez passer cela dans les arguments de la fonction jslint interne si vous pouvez vous en mêler.)

6
hugomg

Il y a beaucoup trop de gens qui appliquent des règles arbitraires sur la manière dont JavaScript doit être écrit. La plupart des règles sont des ordures absolues.

Le levage de fonction est une fonctionnalité de JavaScript car c'est une bonne idée.

Lorsque vous avez une fonction interne qui est souvent l’utilité des fonctions internes, son ajout au début de la fonction externe constitue un style de code d’écriture acceptable. la fonction extérieure fait.

Vous devez vous en tenir à un principe tout au long de votre base de code, soit de placer les fonctions privées en premier ou en dernier dans votre module ou votre fonction. JSHint est utile pour assurer la cohérence, mais vous devez ABSOLUMENT ajuster le .jshintrc à vos besoins, NE PAS ajuster votre code source aux concepts de code farfelus des autres peuples.

Un style de codage que vous pourriez voir à l'état sauvage devrait être évité car il ne vous donne aucun avantage et ne fait que nuire à votre refactoring:

function bigProcess() {
    var step1,step2;
    step1();
    step2();

    step1 = function() {...};
    step2 = function() {...};
}

C'est exactement ce que la fonction de levage est là pour éviter. Apprenez simplement la langue et exploitez ses forces.

3
Henrik Vendelbo

Seules les déclarations de fonction sont levées, pas l'expression de fonction (affectation).

2
Abhay Srivastav