Passa una funzione JavaScript come parametro


665

Come faccio a passare una funzione come parametro senza che la funzione venga eseguita nella funzione "padre" o utilizzi eval()? (Dal momento che ho letto che è insicuro.)

Ho questo:

addContact(entityId, refreshContactList());

Funziona, ma il problema è che si refreshContactListattiva quando viene chiamata la funzione, piuttosto che quando viene utilizzata nella funzione.

Potrei aggirarlo usando eval(), ma non è la migliore pratica, secondo quello che ho letto. Come posso passare una funzione come parametro in JavaScript?

Risposte:


930

Devi solo rimuovere la parentesi:

addContact(entityId, refreshContactList);

Questo quindi passa la funzione senza prima eseguirla.

Ecco un esempio:

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

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

addContact(1, refreshContactList);

6
@stevefenton, considera di aggiornare la tua risposta con un commento h2ooooooo, sarebbe molto utile.
Morgan Wilde,

5
Sulla base della domanda, il callback non accetta i parametri, motivo per cui li ho esclusi dall'esempio. Aggiungerò un commento a riguardo.
Fenton,

4
@Veverke Sembrerebbe così ...addContact(1, function(id) { console.log(id); });
Fenton,

4
@Steve Fenton: dopo aver letto la tua risposta mi sono chiesto perché ho chiesto ... :-)
Veverke

1
La sintassi della classe in ECMAScript non avrebbe un =segno ... class myFuncs {piuttosto che class myFuncs = {. Dovresti anche essere in esecuzione in un ambiente che supporta la sintassi della classe (non tutti i browser lo supportano ancora). Se stai ancora lottando, potrebbe essere più adatto a una domanda completamente nuova poiché il tuo problema non riguarda il passaggio di funzioni: è la sintassi ES generale.
Fenton,

338

Se vuoi passare una funzione, fai semplicemente riferimento per nome senza le parentesi:

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

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

Ma a volte potresti voler passare una funzione con argomenti inclusi , ma non farla chiamare fino a quando non viene richiamato il callback. Per fare questo, quando lo chiami, basta avvolgerlo in una funzione anonima, in questo modo:

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

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

Se preferisci, puoi anche usare la funzione apply e avere un terzo parametro che è un array di argomenti, come questo:

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"]); 

72
questo dovrebbe essere classificato più in alto poiché affronta anche come passare una funzione con argomenti
deltanina,

3
E qualcosa che aggiungerò a questo è che questa caratteristica da sola - essere in grado di passare funzioni JavaScript come argomenti o variabili o simili - è la caratteristica che rende JavaScript così potente e così eccezionale da
inserire

@ Compynerd255 Sono d'accordo, questo e la capacità di creare rapidamente oggetti letterali sono i miei due aspetti preferiti di Javascript. Mi mancano sempre letterali oggetto in lingue che non li hanno.
dallin

3
Sono molto grato a Javascript per aver fornito questa funzione e a te @dallin per avermi fatto sapere che esiste.
Dipendu Paul,

Per l'esempio "avvolgilo in una funzione anonima", nel caso in cui non sia ovvio, la funzione anonima restituisce la funzione stessa (con parametri) e viene invocata quando raggiunge la parentesi in func (). Mi ci è voluto un po 'di tempo per capire, quindi ho pensato che potesse aiutare gli altri.
hubpixel

51

Esempio 1:

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

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

Esempio 2:

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

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

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

guarda questo


al primo esempio dovresti aggiungere la parola chiave return, in questo modo: function funct (a, foo) {return foo (a) // questo restituirà a} altrimenti non sarai definito
Artem Fedotov

34

Per passare la funzione come parametro, è sufficiente rimuovere le parentesi!

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'idea alla base di ciò è che una funzione è abbastanza simile a una variabile. Invece di scrivere

function ToBeCalled() { /* something */ }

potresti anche scrivere

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

Ci sono differenze minori tra i due, ma comunque - entrambi sono modi validi per definire una funzione. Ora, se definisci una funzione e la assegni esplicitamente a una variabile, sembra abbastanza logico, che puoi passarla come parametro a un'altra funzione e non hai bisogno di parentesi:

anotherFunction(ToBeCalledVariable);

2
Basta typeof paramFunc == "function", perché se non è richiamabile, puoi ignorarlo.
Jimmy Knoot,

16

C'è una frase tra i programmatori JavaScript: "Eval is Evil" quindi cerca di evitarlo a tutti i costi!

Oltre alla risposta di Steve Fenton, puoi anche passare direttamente le funzioni.

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

function callAddContact() {
    addContact("entity", function() { DoThis(); });
}

8

Mi sono tagliato tutti i capelli con quel problema. Non ho potuto far funzionare gli esempi sopra, quindi ho finito come:

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')");

E funziona come un incantesimo ... almeno per quello di cui avevo bisogno. Spero che possa aiutare alcuni.


6

Suggerisco di mettere i parametri in un array e poi di dividerli usando la .apply()funzione. Quindi ora possiamo facilmente passare una funzione con molti parametri ed eseguirla in modo semplice.

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

5

Puoi anche usare eval()per fare la stessa cosa.

//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");

Questo è tutto. Stavo anche cercando questa soluzione e ho provato le soluzioni fornite in altre risposte, ma alla fine l'ho fatto funzionare dall'esempio sopra.


2

Ecco un altro approccio:

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

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

2

In effetti, sembra un po 'complicato, non lo è.

ottieni il metodo come parametro:

 function JS_method(_callBack) { 

           _callBack("called");  

        }

Puoi dare come metodo di parametro:

    JS_method(function (d) {
           //Finally this will work.
           alert(d)
    });

1
Per favore, spiega la tua risposta.
Millares,

2

Le altre risposte fanno un ottimo lavoro descrivendo quello che sta succedendo, ma un importante "gotcha" è assicurarsi che qualunque cosa passi attraverso sia effettivamente un riferimento a una funzione.

Ad esempio, se si passa attraverso una stringa anziché una funzione, verrà visualizzato un errore:

function function1(my_function_parameter){
    my_function_parameter();   
}

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

function1(function2); //This will work

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

Vedi JsFiddle


0

Qualche volta in cui è necessario gestire il gestore di eventi, quindi è necessario passare anche l'evento come argomento, la maggior parte delle librerie moderne come la reazione, angolare potrebbe aver bisogno di questo.

Ho bisogno di sovrascrivere la funzione OnSubmit (funzione dalla libreria di terze parti) con un po 'di convalida personalizzata su reazioni e ho passato la funzione e l'evento entrambi come sotto

ORIGINARIAMENTE

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

FATTO UNA NUOVA FUNZIONE uploade chiamato passato onSubmited evento come argomenti

<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);
}

-3

È possibile utilizzare anche un JSON per memorizzare e inviare funzioni JS.

Controlla quanto segue:

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



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

Questo stamperà 'a'.

Quanto segue ha lo stesso effetto con quanto sopra:

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

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

function main(){
    myFunc2(myFunc1);
}

Che ha anche lo stesso effetto con il seguente:

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


function myFunc2 (functionParameter){
    functionParameter();
}

function main(){
    myFunc2(myFunc1);
}

E un paradigma a oggetti che usa Class come prototipo di oggetto:

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

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


function main(){    
    var myClass = new Class();  
    myClass.myFunc2(myClass.myFunc1);
}

9
Il tuo esempio di codice principale non è JSON. Questo è un oggetto JavaScript standard. Inoltre, non è possibile inviare / ricevere funzioni in JSON.
Matthew Layton,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.