Passer une fonction JavaScript comme paramètre

665

Comment passer une fonction en paramètre sans que la fonction s'exécute dans la fonction "parent" ou ne l'utilise eval()? (Depuis que j'ai lu que ce n'est pas sûr.)

J'ai ceci:

addContact(entityId, refreshContactList());

Cela fonctionne, mais le problème est que se refreshContactListdéclenche lorsque la fonction est appelée, plutôt que lorsqu'elle est utilisée dans la fonction.

Je pourrais le contourner en utilisant eval(), mais ce n'est pas la meilleure pratique, selon ce que j'ai lu. Comment passer une fonction comme paramètre en JavaScript?

imperium2335
la source

Réponses:

930

Il vous suffit de supprimer la parenthèse:

addContact(entityId, refreshContactList);

Cela passe ensuite la fonction sans l'exécuter au préalable.

Voici un exemple:

function addContact(id, refreshCallback) {
    refreshCallback();
    // You can also pass arguments if you need to
    // refreshCallback(id);
}

function refreshContactList() {
    alert('Hello World');
}

addContact(1, refreshContactList);
Fenton
la source
6
@stevefenton, pensez à mettre à jour votre réponse avec un commentaire h2ooooooo, ce serait très utile.
Morgan Wilde
5
Sur la base de la question, le rappel n'accepte pas les paramètres, c'est pourquoi je les ai exclus de l'exemple. J'ajouterai un commentaire à ce sujet.
Fenton
4
@Veverke Cela ressemblerait à ça ...addContact(1, function(id) { console.log(id); });
Fenton
4
@Steve Fenton: après avoir lu votre réponse, je me suis demandé pourquoi ai-je demandé ... :-)
Veverke
1
La syntaxe de classe dans ECMAScript n'aurait pas de =signe ... class myFuncs {plutôt que class myFuncs = {. Vous devez également exécuter dans un environnement prenant en charge la syntaxe de classe (tous les navigateurs ne la prennent pas encore en charge). Si vous rencontrez toujours des difficultés, il pourrait être mieux adapté à une toute nouvelle question car votre problème ne concerne pas le passage de fonctions - c'est la syntaxe ES générale.
Fenton
338

Si vous voulez passer une fonction, faites-la simplement référence par son nom sans les parenthèses:

function foo(x) {
    alert(x);
}
function bar(func) {
    func("Hello World!");
}

//alerts "Hello World!"
bar(foo);

Mais parfois, vous souhaiterez peut-être passer une fonction avec des arguments inclus , mais ne pas la faire appeler jusqu'à ce que le rappel soit appelé. Pour ce faire, lorsque vous l'appelez, enveloppez-le simplement dans une fonction anonyme, comme ceci:

function foo(x) {
   alert(x);
}
function bar(func) {
   func();
}

//alerts "Hello World!" (from within bar AFTER being passed)
bar(function(){ foo("Hello World!") });

Si vous préférez, vous pouvez également utiliser la fonction apply et avoir un troisième paramètre qui est un tableau d'arguments, comme celui-ci:

function eat(food1, food2)
{
    alert("I like to eat " + food1 + " and " + food2 );
}
function myFunc(callback, args)
{
    //do stuff
    //...
    //execute callback when finished
    callback.apply(this, args);
}

//alerts "I like to eat pickles and peanut butter"
myFunc(eat, ["pickles", "peanut butter"]); 
dallin
la source
72
cela devrait être classé plus haut car il explique également comment passer une fonction avec des arguments
deltanine
3
Et quelque chose que j'ajouterai à cela, c'est que cette fonctionnalité seule - être capable de passer des fonctions JavaScript sous forme d'arguments ou de variables ou similaires - est la fonctionnalité qui rend JavaScript si puissant et si génial à coder.
TheHansinator
@ Compynerd255 Je suis d'accord, cela et la possibilité de créer rapidement des littéraux d'objets sont mes deux aspects préférés de Javascript. Les littéraux d'objets me manquent toujours dans les langues qui n'en ont pas.
dallin
3
Je suis très reconnaissant à Javascript d'avoir fourni cette fonctionnalité et à @dallin de m'avoir fait savoir qu'elle existe.
Dipendu Paul
Pour l'exemple "envelopper dans une fonction anonyme", dans le cas où cela n'est pas évident, la fonction anonyme retourne la fonction elle-même (avec paramètres) et elle est invoquée lorsqu'elle atteint la parenthèse dans func (). Cela m'a pris du temps à comprendre, alors j'ai pensé que cela pourrait aider les autres.
hubpixel
51

Exemple 1:

funct("z", function (x) { return x; });

function funct(a, foo){
    foo(a) // this will return a
}

Exemple 2:

function foodemo(value){
    return 'hello '+value;
}

function funct(a, foo){
    alert(foo(a));
}

//call funct    
funct('world!',foodemo); //=> 'hello world!'

regarde ça

Gadde
la source
dans le premier exemple, vous devez ajouter le mot-clé return, comme ceci: function funct (a, foo) {return foo (a) // cela retournera a} sinon vous ne serez pas défini
Artem Fedotov
34

Pour passer la fonction en paramètre, supprimez simplement les crochets!

function ToBeCalled(){
  alert("I was called");
}

function iNeedParameter( paramFunc) {
   //it is a good idea to check if the parameter is actually not null
   //and that it is a function
   if (paramFunc && (typeof paramFunc == "function")) {
      paramFunc();   
   }
}

//this calls iNeedParameter and sends the other function to it
iNeedParameter(ToBeCalled); 

L'idée derrière cela est qu'une fonction est assez similaire à une variable. Au lieu d'écrire

function ToBeCalled() { /* something */ }

vous pourriez aussi bien écrire

var ToBeCalledVariable = function () { /* something */ }

Il existe des différences mineures entre les deux, mais de toute façon - les deux sont des moyens valides pour définir une fonction. Maintenant, si vous définissez une fonction et l'affectez explicitement à une variable, il semble tout à fait logique que vous puissiez la passer en paramètre à une autre fonction, et vous n'avez pas besoin de crochets:

anotherFunction(ToBeCalledVariable);
naïvistes
la source
2
C'est juste typeof paramFunc == "function"assez, car si ce n'est pas appelable, alors vous pouvez l'ignorer.
Jimmy Knoot
16

Il y a une phrase parmi les programmeurs JavaScript: "Eval is Evil" alors essayez de l'éviter à tout prix!

En plus de la réponse de Steve Fenton, vous pouvez également transmettre des fonctions directement.

function addContact(entity, refreshFn) {
    refreshFn();
}

function callAddContact() {
    addContact("entity", function() { DoThis(); });
}
Matthew Layton
la source
8

J'ai coupé tous mes cheveux avec ce problème. Je n'ai pas pu faire fonctionner les exemples ci-dessus, alors j'ai fini comme:

function foo(blabla){
    var func = new Function(blabla);
    func();
}
// to call it, I just pass the js function I wanted as a string in the new one...
foo("alert('test')");

Et cela fonctionne comme un charme ... pour ce dont j'avais besoin au moins. J'espère que cela pourrait aider certains.

Fenix ​​Aoras
la source
6

Je suggère de mettre les paramètres dans un tableau, puis de les diviser en utilisant la .apply()fonction. Alors maintenant, nous pouvons facilement passer une fonction avec beaucoup de paramètres et l'exécuter de manière simple.

function addContact(parameters, refreshCallback) {
    refreshCallback.apply(this, parameters);
}

function refreshContactList(int, int, string) {
    alert(int + int);
    console.log(string);
}

addContact([1,2,"str"], refreshContactList); //parameters should be putted in an array
Naramsim
la source
5

Vous pouvez également utiliser eval()pour faire la même chose.

//A function to call
function needToBeCalled(p1, p2)
{
    alert(p1+"="+p2);
}

//A function where needToBeCalled passed as an argument with necessary params
//Here params is comma separated string
function callAnotherFunction(aFunction, params)
{
    eval(aFunction + "("+params+")");
}

//A function Call
callAnotherFunction("needToBeCalled", "10,20");

C'est ça. Je cherchais également cette solution et j'ai essayé des solutions fournies dans d'autres réponses, mais j'ai finalement réussi à le faire à partir de l'exemple ci-dessus.

Pointeur nul
la source
2

Voici une autre approche:

function a(first,second)    
{        
return (second)(first);           
}     

a('Hello',function(e){alert(e+ ' world!');}); //=> Hello world     
cochon
la source
2

En fait, cela semble un peu compliqué, non.

get méthode comme paramètre:

 function JS_method(_callBack) { 

           _callBack("called");  

        }

Vous pouvez donner comme méthode de paramètre:

    JS_method(function (d) {
           //Finally this will work.
           alert(d)
    });
Hakkı Eser
la source
1
Veuillez expliquer votre réponse.
MillaresRoo
2

Les autres réponses décrivent très bien ce qui se passe, mais un "piège" important consiste à s'assurer que tout ce que vous traversez est bien une référence à une fonction.

Par exemple, si vous passez par une chaîne au lieu d'une fonction, vous obtiendrez une erreur:

function function1(my_function_parameter){
    my_function_parameter();   
}

function function2(){
 alert('Hello world');   
}

function1(function2); //This will work

function1("function2"); //This breaks!

Voir JsFiddle

Victor
la source
0

Parfois, lorsque vous devez traiter avec un gestionnaire d'événements, vous devez également passer l'événement comme argument, la plupart des bibliothèques modernes comme react, angular pourraient en avoir besoin.

J'ai besoin de remplacer la fonction OnSubmit (fonction de la bibliothèque tierce) avec une validation personnalisée sur reactjs et j'ai passé la fonction et l'événement tous les deux comme ci-dessous

INITIALEMENT

    <button className="img-submit" type="button"  onClick=
 {onSubmit}>Upload Image</button>

FAIT UNE NOUVELLE FONCTION uploadet appelé passé onSubmitet événement comme arguments

<button className="img-submit" type="button"  onClick={this.upload.bind(this,event,onSubmit)}>Upload Image</button>

upload(event,fn){
  //custom codes are done here
  fn(event);
}
sumit
la source
-3

Vous pouvez également utiliser un JSON pour stocker et envoyer des fonctions JS.

Vérifiez les points suivants:

var myJSON = 
{
    "myFunc1" : function (){
        alert("a");
    }, 
    "myFunc2" : function (functionParameter){
        functionParameter();
    }
}



function main(){
    myJSON.myFunc2(myJSON.myFunc1);
}

Cela imprimera «a».

Ce qui suit a le même effet avec ce qui précède:

var myFunc1 = function (){
    alert('a');
}

var myFunc2 = function (functionParameter){
    functionParameter();
}

function main(){
    myFunc2(myFunc1);
}

Ce qui a également le même effet avec ce qui suit:

function myFunc1(){
    alert('a');
}


function myFunc2 (functionParameter){
    functionParameter();
}

function main(){
    myFunc2(myFunc1);
}

Et un paradigme d'objet utilisant Class comme prototype d'objet:

function Class(){
    this.myFunc1 =  function(msg){
        alert(msg);
    }

    this.myFunc2 = function(callBackParameter){
        callBackParameter('message');
    }
}


function main(){    
    var myClass = new Class();  
    myClass.myFunc2(myClass.myFunc1);
}
gaz gaz
la source
9
Votre exemple de code supérieur n'est pas JSON. Il s'agit d'un objet JavaScript standard. Vous ne pouvez pas non plus envoyer / recevoir de fonctions dans JSON.
Matthew Layton