Différence entre setTimeout avec et sans guillemets et parenthèses

241

J'apprends JavaScript et j'ai récemment appris les événements de synchronisation JavaScript. Quand j'ai appris setTimeoutà W3Schools , j'ai remarqué un étrange personnage que je ne courais pas en avant. Ils utilisent des guillemets doubles et appellent ensuite la fonction.

Exemple:

setTimeout("alertMsg()", 3000);

Je sais que les guillemets doubles et simples en JavaScript signifient une chaîne.

J'ai aussi vu que je peux faire la même chose comme ça:

setTimeout(alertMsg, 3000);

Avec les parenthèses, il fait référence, sans les parenthèses, il est copié. Quand j'utilise les guillemets et les parenthèses, ça devient fou.

Je serai heureux si quelqu'un peut m'expliquer la différence entre ces trois façons d'utiliser setTimeout:

Avec les parenthèses:

setTimeout("alertMsg()", 3000);

Sans les guillemets et les parenthèses:

setTimeout(alertMsg, 3000);

Et le troisième utilise uniquement des guillemets:

setTimeout("alertMsg", 3000);

NB: Une meilleure source de setTimeoutréférence serait MDN .

user1316123
la source
5
@Jefffrey que le site Web de w3fools ne dit pas que le contenu y est faux, juste qu'il pourrait être obsolète et manquer certaines des nouveautés. Cela devrait être bien d'utiliser comme référence (ou pour apprendre) les trucs de base. Je peux comprendre que les gens soient frustrés par la façon dont ils essaient de faire partie de w3, mais cela n'enlève rien au contenu. C'est joliment agencé et facile à lire avec des exemples clairs, préfet pour les noobs.
Matthew
14
@Matthew "Nous pensons cependant que W3Schools nuit à la communauté avec des informations inexactes." - dans les trois premières lignes.
Chaussure
1
@Jefffrey oui, je l'ai vu, mais plus bas, où ils expliquent ce qu'ils n'aiment pas, dans la section "W3Schools is trouble", aucune des trois raisons qu'ils donnent n'a rien à voir avec des informations inexactes. Ils n'ont pas un seul exemple de quoi que ce soit qui soit "faux". Leurs plaintes sont qu'ils ne disent pas explicitement qu'ils ne sont pas affiliés à w3, qu'ils facturent des certifications non reconnues et qu'ils ne mettent pas à jour rapidement avec le nouveau contenu (par exemple html 5).
Matthew
10
@Matthew, Des informations obsolètes, dans des langages délicats comme Javascript, SQL ou PHP, sont ce qui guide des masses de programmeurs en herbe à s'en tenir aux technologies anciennes et potentiellement dangereuses (telles que l' mysql_extension de PHP) dont le flux de questions SO n'est qu'un exemple. IIRC il y a eu aussi des erreurs très subtiles dans la section SQL, mais cela fait presque un an depuis la dernière fois que j'ai visité le site Web et beaucoup d'entre elles pourraient aussi bien être corrigées. Et même si tout était parfait, je ne ferais pas encore la promotion d'un site Web qui essaie de tromper les gens avec la fraude de leur certificat.
Chaussure du
4
Mis à part les certifications louches, c'est une ressource de référence décente et il est contre-productif au point de SO de les dénoncer.
worc

Réponses:

383

Utilisation de setIntervalousetTimeout

Vous devez passer une référence à une fonction comme premier argument pour setTimeoutou setInterval. Cette référence peut prendre la forme de:

  • Une fonction anonyme

    setTimeout(function(){/* Look mah! No name! */},2000);
  • Un nom d'une fonction existante

    function foo(){...}
    
    setTimeout(foo, 2000);
  • Une variable qui pointe vers une fonction existante

    var foo = function(){...};
    
    setTimeout(foo, 2000);

    Notez que j'ai défini "variable dans une fonction" séparément de "nom de la fonction". Il n'est pas évident que les variables et les noms de fonction occupent le même espace de noms et peuvent s'encombrer.

Passer des arguments

Pour appeler une fonction et transmettre des paramètres, vous pouvez appeler la fonction dans le rappel affecté au temporisateur:

setTimeout(function(){
  foo(arg1, arg2, ...argN);
}, 1000);

Il existe une autre méthode pour passer des arguments dans le gestionnaire, mais elle n'est pas compatible avec tous les navigateurs .

setTimeout(foo, 2000, arg1, arg2, ...argN);

Contexte de rappel

Par défaut, le contexte du rappel (la valeur de l' thisintérieur de la fonction appelée par le temporisateur) lorsqu'il est exécuté est l'objet global window. Si vous souhaitez le modifier, utilisez bind.

setTimeout(function(){
  this === YOUR_CONTEXT; // true
}.bind(YOUR_CONTEXT), 2000);

Sécurité

Bien que ce soit possible, vous ne devez pas passer de chaîne à setTimeoutou setInterval. La transmission d'une chaîne crée setTimeout()ou setInterval()utilise une fonctionnalité similaire à eval()celle qui exécute les chaînes en tant que scripts , ce qui rend possible l'exécution de scripts arbitraires et potentiellement dangereux.

Joseph
la source
J'ai appris que lorsque vous utilisez uniquement le nom de la fonction, la fonction est copiée, alors pourquoi dites-vous dans votre premier exemple que setTumeout foo (fonction) passe la référence que la fonction a penchée est copiée. et pouvez-vous me mesurer plus s'il vous plaît à propos de l'évaluation s'il vous plaît.
user1316123
42
Les fonctions @ user1316123 ne sont jamais copiées. idem pour les objets et les tableaux. ils sont transmis par référence . vous devez arrêter de lire w3schools. ils font plus de mal que de bien
Joseph
4
Les fonctions @JosephtheDreamer sont des objets. «Un nom de fonction» et «Une variable qui fait référence à une fonction», c'est la même chose. En outre, vous pouvez passer directement des paramètres à setTimeout (pas besoin d'envelopper un lambda pour cela (bien que, comme vous l'avez dit - les nouveaux navigateurs). En outre, le problème n'est pas de laisser les utilisateurs exécuter des scripts (ils peuvent toujours le faire de toute façon), il est en acceptant l' entrée d' autres utilisateurs et en cours d' exécution qui en tant que script l'utilisateur peut toujours se suffit d' ouvrir la console et d' exécuter JavaScript arbitraire..
Benjamin Gruenbaum
@BenjaminGruenbaum J'étais sur le point de faire un commentaire presque identique à votre deuxième phrase. Rire :)
ErikE
2
Je ne savais pas que vous deviez utiliser une fonction pour que setTimeout fonctionne correctement. Merci d'avoir clarifié cela.
Matt Dell
3

je pense que la fonction setTimeout que vous écrivez n'est pas en cours d'exécution. si vous utilisez jquery, vous pouvez le faire fonctionner correctement en procédant comme suit:

    function alertMsg() {
      //your func
    }

    $(document).ready(function() {
       setTimeout(alertMsg,3000); 
       // the function you called by setTimeout must not be a string.
    });
Acil Az
la source
je pense comme vous, mais le lien w3schools.com/js/js_timing.asp disant quelque chose d'autre
user1316123
si je comprends bien lorsque j'utilise des crochets, je peux me référer uniquement à la fonction qui contient la méthode setTimeout parce que la fonction est disponible aux crochets uniquement à sa portée locale?
user1316123
2

Tout à fait d'accord avec Joseph.

Voici un violon pour tester ceci: http://jsfiddle.net/nicocube/63s2s/

Dans le contexte du violon, l'argument chaîne ne fonctionne pas, à mon avis, car la fonction n'est pas définie dans la portée globale.

Nicocube
la source
w3schools.com/js/js_timing.asp si vous pouvez entrer le lien s'il vous plaît et voyez parce que Joseph dit que c'est dangereux mais si vous entrez le lien son fonctionnement
user1316123
les gars s'il vous plaît regardez ceci: quirksmode.org/js/this.html ce lien dit qu'un func peut être copié
user1316123
Oui, car les fonctions sont des objets dans JS. Le problème avec eval est qu'il s'évaluera dans un contexte global et ne parviendra pas à obtenir le contexte local qui se produit avec un violon.
Nicocube
pouvez-vous expliquer en quelques mots sur eval s'il vous plaît.
user1316123
Quelques bonnes explications: javascriptweblog.wordpress.com/2010/04/19/how-evil-is-eval
Nicocube
1

Que se passe-t-il en réalité si vous passez une chaîne comme premier paramètre de fonction

setTimeout ( 'string', number)

est la valeur du premier paramètre obtenu évalué quand il est temps de s'exécuter (après le passage numberdes millisecondes). Fondamentalement, il est égal à

setTimeout ( eval('string'), number)

C'est

une syntaxe alternative qui vous permet d'inclure une chaîne au lieu d'une fonction, qui est compilée et exécutée lorsque le temporisateur expire. Cette syntaxe n'est pas recommandée pour les mêmes raisons qui font de l'utilisation d'eval () un risque pour la sécurité.

Les échantillons que vous référez ne sont donc pas de bons échantillons et peuvent être donnés dans un contexte différent ou simplement par une simple faute de frappe.

Si vous invoquez comme ceci setTimeout(something, number), le premier paramètre n'est pas une chaîne, mais un pointeur sur quelque chose appelé something. Et encore si somethingest une chaîne - alors elle sera évaluée. Mais si c'est une fonction, alors la fonction sera exécutée. échantillon jsbin

Vitaliy Markitanov
la source
0
    ##If i want to wait for some response from server or any action we use setTimeOut.

    functionOne =function(){
    console.info("First");

    setTimeout(()=>{
    console.info("After timeOut 1");
    },5000);
    console.info("only setTimeOut() inside code waiting..");
    }

    functionTwo =function(){
    console.info("second");
    }
    functionOne();
    functionTwo();

## So here console.info("After timeOut 1"); will be executed after time elapsed.
Output:
******************************************************************************* 
First
only setTimeOut() inside code waiting..
second
undefined
After timeOut 1  // executed after time elapsed.
Avinash Khadsan
la source
-1

Avec les parenthèses:

setTimeout("alertMsg()", 3000); // It work, here it treat as a function

Sans les guillemets et les parenthèses:

setTimeout(alertMsg, 3000); // It also work, here it treat as a function

Et le troisième utilise uniquement des guillemets:

setTimeout("alertMsg", 3000); // It not work, here it treat as a string

function alertMsg1() {
        alert("message 1");
    }
    function alertMsg2() {
        alert("message 2");
    }
    function alertMsg3() {
        alert("message 3");
    }
    function alertMsg4() {
        alert("message 4");
    }

    // this work after 2 second
    setTimeout(alertMsg1, 2000);

    // This work immediately
    setTimeout(alertMsg2(), 4000);

    // this fail
    setTimeout('alertMsg3', 6000);

    // this work after 8second
    setTimeout('alertMsg4()', 8000);

Dans l'exemple ci-dessus, appelez d'abord la fonction alertMsg2 () immédiatement (nous donnons le délai d'attente 4S mais cela ne dérange pas) après cette alerteMsg1 () (Un temps d'attente de 2 secondes) puis alertMsg4 () (Un temps d'attente de 8 secondes) mais le alertMsg3 () ne fonctionne pas parce que nous le plaçons dans les guillemets sans parties, il est donc traité comme une chaîne.

Srikrushna
la source
Montre les scénarios sur lesquels l'interrogateur pose des questions, mais ne répond pas réellement à la question. Je ne vois pas ce que cela ajoute aux réponses existantes de 6 ans .
Stephen P