2010-09-04 9 views
19

Maintenant, j'appelle généralement une fonction (qui ne nécessite pas des arguments) avec () comme ceci:Quelle est la signification de "()" dans un appel de fonction?

myFunction(); //there's empty parens 

Sauf dans les appels jQuery où je peux sortir avec:

$('#foo').bind('click', myFunction); //no parens 

fin. Mais récemment, j'ai vu ce commentaire sur here SO:

"Pensez à utiliser setTimeout(monitor, 100); au lieu de setTimeout('monitor()', 100); Eval est mal :)."

Aïe! Sommes-nous vraiment eval() -ing une chaîne ici? Je suppose que je ne comprends pas vraiment la signification et les implications de «appeler» une fonction. Quelles sont les vraies règles d'appel et de référence aux fonctions?

Répondre

44

Dans JavaScript, les fonctions sont des objets de première classe. Cela signifie que vous pouvez passer des fonctions autour des paramètres d'une fonction, ou les traiter comme des variables en général.

Disons que nous parlons d'une fonction hello,

function hello() { 
    alert('yo'); 
} 

Quand nous écrivons simplement

hello 

nous faisons référence à la fonction qui ne l'exécute pas son contenu. Mais quand on ajoute les parens () après le nom de la fonction,

hello() 

nous appelons effectivement la fonction qui alertera « yo » à l'écran.

La méthode bind de jQuery accepte le type d'événement (chaîne) et une fonction en tant qu'arguments. Dans votre exemple, vous passez le type - "clic" et la fonction réelle en tant qu'argument.

Avez-vous vu Inception? Considérez cet exemple artificiel qui pourrait rendre les choses plus claires. Puisque les fonctions sont des objets de première classe dans JavaScript, nous pouvons passer et retourner une fonction depuis une fonction. Créons donc une fonction qui renvoie une fonction lorsqu'elle est invoquée, et la fonction retournée renvoie également une autre fonction lorsqu'elle est invoquée.

function reality() { 
    return function() { 
     return function() { 
      alert('in a Limbo'); 
     } 
    }; 
} 

Ici reality est une fonction, reality() est une fonction et reality()() est une fonction aussi bien. Cependant reality()()() n'est pas une fonction, mais simplement undefined car nous ne retournons pas une fonction (nous ne retournons rien) de la fonction la plus interne. Donc pour l'exemple de fonction reality, vous pourriez avoir transmis l'un des éléments suivants à la liaison de jQuery.

$('#foo').bind('click', reality); 
$('#foo').bind('click', reality()); 
$('#foo').bind('click', reality()()); 
+8

Étrangement, cela a éclairci les choses. –

+2

Yay, je tiens maintenant le record pour utiliser "fonction" le plus de fois sur toutes les réponses SO - 27. – Anurag

+3

+1 pour la référence de démarrage (et pour une bonne explication, bien sûr) – delnan

3

vous ne faites pas la même chose dans votre exemple jQuery comme dans le second exemple setTimeout - dans votre code que vous passez la fonction et la liaison de l'événement click.

Dans le premier setTimout exemple, la fonction monitor est passé et peut être invoquée directement, dans la seconde, la piqûre monitor() est passé et doit être eval ed.

Lors du passage d'une fonction, vous utilisez le nom de la fonction. Lorsque vous l'invoquez, vous devez utiliser le (). Eval invoquera ce qui est passé, donc un () est requis pour une invocation de fonction réussie.

+0

Donc le commentaire est faux? Il devrait vraiment passer 'setTimeout (monitor(), 100); // note les parens'? –

+0

@Isaac Lubow: Non, le code est juste - c'est juste que vous faites quelque chose de différent dans chaque morceau de code. Les deux exemples ne sont pas identiques. –

+0

Si vous voulez que 'monitor' s'exécute après 100 ms, vous devez faire' setTimeout (monitor(), 100); // note les parens? 'alors? –

7

Votre exemple jQuery bind est similaire à setTimeout(monitor, 100);, vous passez une référence d'un objet fonction en tant qu'argument.

Passer une chaîne aux méthodes doivent être évités pour les mêmes raisons setTimeout/setInterval vous devez éviter eval et le constructeur Function quand il est inutile.

Le code passé en tant que chaîne sera évalué et exécuté dans le contexte de l'exécution globale, qui peut vous donner « les questions de portée », considérons l'exemple suivant:

// a global function 
var f = function() { 
    alert('global'); 
}; 

(function() { 
    // a local function 
    var f = function() { 
    alert('local'); 
    }; 

    setTimeout('f()', 100); // will alert "global" 
    setTimeout(f, 100);  // will alert "local" 
})(); 

Le premier setTimeout appel dans l'exemple ci-dessus , exécutera la fonction globale f, car le code évalué n'a pas accès à la portée lexicale locale de la fonction anonyme.

Si vous transmettez la référence d'un objet fonction à la méthode setTimeout -comme dans le second appel setTimeout- la même fonction que celle que vous vous référez dans la portée actuelle sera exécutée.

2

Tout d'abord, "()" ne fait pas partie du nom de la fonction. C'est la syntaxe utilisée pour faire des appels de fonction.

D'abord, vous liez une fonction à un nom d'identifiant soit en utilisant une déclaration de fonction:

function x() { 
    return "blah"; 
} 

... ou en utilisant une expression de fonction:

var x = function() { 
    return "blah"; 
}; 

Maintenant, chaque fois que vous voulez Pour exécuter cette fonction, vous utilisez les parenthèses:

x(); 

La fonction setTimeout accepte les deux et identifiant à une fonction, ou une chaîne comme premier argument ...

setTimeout(x, 1000); 
setTimeout("x()", 1000); 

Si vous fournissez un identifiant, il sera appelé en fonction. Si vous indiquez une chaîne, elle sera évaluée (exécutée).

La première méthode (fournissant un identificateur) est préférable ...

+0

'Si vous fournissez un identifiant, il sera appelé en tant que fonction. Si vous fournissez une chaîne, elle sera évaluée (exécutée). » Pouvez-vous expliquer la différence? –

+0

@Isaac Si vous indiquez une chaîne, cette chaîne sera exécutée comme du code JavaScript. Par exemple: 'setTimeout ('x = 3;', 100)'. Comme vous pouvez le voir, aucune fonction n'est appelée ici. La chaîne «x = 3;» est évaluée comme une expression d'affectation. D'un autre côté, si vous fournissez un nom d'identifiant, ce nom doit pointer vers un objet fonction (qui sera alors appelé). –

+0

Gotcha. Merci. –

Questions connexes