JavaScript: passaggio dei parametri a una funzione di callback


289

Sto cercando di passare alcuni parametri a una funzione utilizzata come callback, come posso farlo?

function tryMe (param1, param2) {
    alert (param1 + " and " + param2);
}

function callbackTester (callback, param1, param2) {
    callback (param1, param2);
}

callbackTester (tryMe, "hello", "goodbye");

9
Quello che stai facendo dovrebbe funzionare. Che problemi hai?
Daniel Vassallo,

1
Il tuo codice funziona bene, qual è il problema?
Sarfraz,

1
Dovrebbe funzionare ... jsfiddle.net/QXQZj
Hristo l'

mi dispiace è stata colpa mia sulla sintassi del codice principale, ho pensato che fosse questa perché è la prima volta che utilizzo un callback in JavaScript
vitto

Se vuoi aggiungere parametri a un callback ma non puoi cambiare ciò che lo chiama (come in te non hai il potere di cambiare l'ordine degli argomenti, puoi pre-associare alcuni dei parametri di callback con il bind JS, come ho mostrato su questa risposta: stackoverflow.com/a/28120741/1695680
ThorSummoner

Risposte:


253

Se vuoi qualcosa di leggermente più generale, puoi usare la variabile argomenti in questo modo:

function tryMe (param1, param2) {
    alert(param1 + " and " + param2);
}

function callbackTester (callback) {
    callback (arguments[1], arguments[2]);
}

callbackTester (tryMe, "hello", "goodbye");

In caso contrario, l'esempio funziona correttamente (gli argomenti [0] possono essere utilizzati al posto della richiamata nel tester)


53
Finché siamo nello spirito di essere generali, callback.apply(arguments)poiché il corpo della funzione callbackTesterè estendibile oltre lo scenario dei due argomenti.
Steven,

1
scusate, è stato un errore di sintassi nel codice principale, pensavo fosse questo perché questa è la prima volta che utilizzo un callback in JavaScript, mi avete aiutato a capire che non era il problema e a vedere un ottimo esempio.
vitto,

3
Cordiali saluti, usando una funzione anonima (la risposta di Marimuthu) o .bind () (la risposta di Andy) sono modi molto più chiari per passare argomenti a un callback.
antoine,

203

Questo funzionerebbe anche:

// callback function
function tryMe (param1, param2) { 
    alert (param1 + " and " + param2); 
} 

// callback executer 
function callbackTester (callback) { 
    callback(); 
} 

// test function
callbackTester (function() {
    tryMe("hello", "goodbye"); 
}); 

Un altro scenario:

// callback function
function tryMe (param1, param2, param3) { 
    alert (param1 + " and " + param2 + " " + param3); 
} 

// callback executer 
function callbackTester (callback) { 
//this is the more obivous scenario as we use callback function
//only when we have some missing value
//get this data from ajax or compute
var extraParam = "this data was missing" ;

//call the callback when we have the data
    callback(extraParam); 
} 

// test function
callbackTester (function(k) {
    tryMe("hello", "goodbye", k); 
}); 

2
Funziona alla grande perché consente anche alla funzione anonima di passare parametri come questo: callbackTester (function (data) {tryMe (data, "hello", "arrivederci");});
Michael Khalili,

Mi piace anche verificare che il callback sia, in effetti, una funzione. if (typeof window[callback] == 'function') window[callback].call(this);
GreeKatrina,

63

La tua domanda non è chiara Se ti stai chiedendo come puoi farlo in un modo più semplice, dovresti dare un'occhiata al metodo ECbAScript 5a edizione .bind () , che è un membro di Function.prototype . Usandolo, puoi fare qualcosa del genere:

function tryMe (param1, param2) {
    alert (param1 + " and " + param2);
}

function callbackTester (callback) {
    callback();
}

callbackTester(tryMe.bind(null, "hello", "goodbye"));

Puoi anche utilizzare il seguente codice, che aggiunge il metodo se non è disponibile nel browser corrente:

// From Prototype.js
if (!Function.prototype.bind) { // check if native implementation available
  Function.prototype.bind = function(){ 
    var fn = this, args = Array.prototype.slice.call(arguments),
        object = args.shift(); 
    return function(){ 
      return fn.apply(object, 
        args.concat(Array.prototype.slice.call(arguments))); 
    }; 
  };
}

Esempio

bind () - Documentazione PrototypeJS


Per interesse, qual è la differenza tra Array.prototype.slice.call(arguments)e arguments.slice()?
sje397,

7
@ sje397: argomenti non è un array * reale *, quindi non ha un metodo slice () . Tuttavia, il metodo slice () su Array.prototype è intenzionalmente generico, quindi puoi passare qualsiasi oggetto che abbia indici numerici e una proprietà length e funzionerà.
Andy E

2
Questa è la risposta più elegante
antoine il

Questo .bind () è davvero eccezionale ed estende molto l'uso e la semplicità dei callback. Come esempio di base per capirlo, se hai:f = function(arg1,arg2){alert(arg1+arg2);}.bind(this,"abc"); f("def") // Gives "abcdef"
Le Droid

Questa è davvero una risposta grt. Fantastico e funziona bene per me. Grazie :)
Vishnu Mishra il

13

Quando si dispone di un callback che verrà chiamato da qualcosa di diverso dal codice con un numero specifico di parametri e si desidera passare parametri aggiuntivi, è possibile passare una funzione wrapper mentre il callback e all'interno del wrapper passano i parametri aggiuntivi.

function login(accessedViaPopup) {
    //pass FB.login a call back function wrapper that will accept the
    //response param and then call my "real" callback with the additional param
    FB.login(function(response){
        fb_login_callback(response,accessedViaPopup);
    });
}

//handles respone from fb login call
function fb_login_callback(response, accessedViaPopup) {
    //do stuff
}

9

Se non si è sicuri di quanti parametri si intende passare alle funzioni di callback, utilizzare la applyfunzione.

function tryMe (param1, param2) {
  alert (param1 + " and " + param2);
}

function callbackTester(callback,params){
    callback.apply(this,params);
}

callbackTester(tryMe,['hello','goodbye']);

4

Avvolgere le funzioni "figlio" che vengono passate come / con argomenti all'interno dei wrapper di funzione per impedire che vengano valutate quando viene chiamata la funzione "padre".

function outcome(){
    return false;
}

function process(callbackSuccess, callbackFailure){
    if ( outcome() )
        callbackSuccess();
    else
        callbackFailure();
}

process(function(){alert("OKAY");},function(){alert("OOPS");})

4

Codice da una domanda con un numero qualsiasi di parametri e un contesto di richiamata:

function SomeFunction(name) {
    this.name = name;
}
function tryMe(param1, param2) {
    console.log(this.name + ":  " + param1 + " and " + param2);
}
function tryMeMore(param1, param2, param3) {
    console.log(this.name + ": " + param1 + " and " + param2 + " and even " + param3);
}
function callbackTester(callback, callbackContext) {
    callback.apply(callbackContext, Array.prototype.splice.call(arguments, 2));
}
callbackTester(tryMe, new SomeFunction("context1"), "hello", "goodbye");
callbackTester(tryMeMore, new SomeFunction("context2"), "hello", "goodbye", "hasta la vista");

// context1: hello and goodbye
// context2: hello and goodbye and even hasta la vista

2

Usa la funzione curry come in questo semplice esempio.

const BTN = document.querySelector('button')
const RES = document.querySelector('p')

const changeText = newText => () => {
  RES.textContent = newText
}

BTN.addEventListener('click', changeText('Clicked!'))
<button>ClickMe</button>
<p>Not clicked<p>


0

Una nuova versione per lo scenario in cui il callback verrà chiamato da un'altra funzione, non dal proprio codice, e si desidera aggiungere parametri aggiuntivi.

Ad esempio, facciamo finta di avere molte chiamate nidificate con callback riusciti ed errori. Userò promesse angolari per questo esempio, ma qualsiasi codice javascript con callback sarebbe lo stesso per lo scopo.

someObject.doSomething(param1, function(result1) {
  console.log("Got result from doSomething: " + result1);
  result.doSomethingElse(param2, function(result2) {
    console.log("Got result from doSomethingElse: " + result2);
  }, function(error2) {
    console.log("Got error from doSomethingElse: " + error2);
  });
}, function(error1) {
  console.log("Got error from doSomething: " + error1);
});

Ora potresti voler disordinare il codice definendo una funzione per registrare gli errori, mantenendo l'origine dell'errore a scopo di debug. Ecco come procedere per il refactoring del codice:

someObject.doSomething(param1, function (result1) {
  console.log("Got result from doSomething: " + result1);
  result.doSomethingElse(param2, function (result2) {
    console.log("Got result from doSomethingElse: " + result2);
  }, handleError.bind(null, "doSomethingElse"));
}, handleError.bind(null, "doSomething"));

/*
 * Log errors, capturing the error of a callback and prepending an id
 */
var handleError = function (id, error) {
  var id = id || "";
  console.log("Got error from " + id + ": " + error);
};

La funzione chiamante aggiungerà comunque il parametro di errore dopo i parametri della funzione di richiamata.


0

Stavo cercando la stessa cosa e ho finito con la soluzione ed ecco un semplice esempio se qualcuno vuole passare attraverso questo.

var FA = function(data){
   console.log("IN A:"+data)
   FC(data,"LastName");
};
var FC = function(data,d2){
   console.log("IN C:"+data,d2)
};
var FB = function(data){
   console.log("IN B:"+data);
    FA(data)
};
FB('FirstName')

Anche pubblicato sull'altra domanda qui


0

Lascia che ti dia un semplice esempio di stile Node.js sull'uso di un callback:

/**
 * Function expects these arguments: 
 * 2 numbers and a callback function(err, result)
 */
var myTest = function(arg1, arg2, callback) {
  if (typeof arg1 !== "number") {
    return callback('Arg 1 is not a number!', null); // Args: 1)Error, 2)No result
  }
  if (typeof arg2 !== "number") {
    return callback('Arg 2 is not a number!', null); // Args: 1)Error, 2)No result
  }
  if (arg1 === arg2) {
    // Do somethign complex here..
    callback(null, 'Actions ended, arg1 was equal to arg2'); // Args: 1)No error, 2)Result
  } else if (arg1 > arg2) {
    // Do somethign complex here..
    callback(null, 'Actions ended, arg1 was > from arg2'); // Args: 1)No error, 2)Result
  } else {
    // Do somethign else complex here..
    callback(null, 'Actions ended, arg1 was < from arg2'); // Args: 1)No error, 2)Result
  }
};


/**
 * Call it this way: 
 * Third argument is an anonymous function with 2 args for error and result
 */
myTest(3, 6, function(err, result) {
  var resultElement = document.getElementById("my_result");
  if (err) {
    resultElement.innerHTML = 'Error! ' + err;
    resultElement.style.color = "red";
    //throw err; // if you want
  } else {
    resultElement.innerHTML = 'Result: ' + result;
    resultElement.style.color = "green";
  }
});

e l'HTML che renderà il risultato:

<div id="my_result">
  Result will come here!
</div>

Puoi giocarci qui: https://jsfiddle.net/q8gnvcts/ - ad esempio prova a passare la stringa anziché il numero: myTest ('some string', 6, function (err, result) .. e vedi il risultato.

Spero che questo esempio aiuti perché rappresenta l'idea di base delle funzioni di callback.


0
function tryMe(param1, param2) {
  console.log(param1 + " and " + param2);
}

function tryMe2(param1) {
  console.log(param1);
}

function callbackTester(callback, ...params) {
  callback(...params);
}



callbackTester(tryMe, "hello", "goodbye");

callbackTester(tryMe2, "hello");

leggi di più sulla sintassi diffusa


0
//Suppose function not taking any parameter means just add the GetAlterConfirmation(function(result) {});
GetAlterConfirmation('test','messageText',function(result) {
                        alert(result);
    }); //Function into document load or any other click event.


function GetAlterConfirmation(titleText, messageText, _callback){
         bootbox.confirm({
                    title: titleText,
                    message: messageText,
                    buttons: {
                        cancel: {
                            label: '<i class="fa fa-times"></i> Cancel'
                        },
                        confirm: {
                            label: '<i class="fa fa-check"></i> Confirm'
                        }
                    },
                    callback: function (result) {
                        return _callback(result); 
                    }
                });

1
Per favore, aggiungi una spiegazione di cosa stai facendo e perché :)
Preston Badeer,

Ok, lo farò dalla mia prossima risposta, scusami per quanto sopra perché questa è la mia prima risposta.
Santhos Jery,
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.