JavaScript: pasar parámetros a una función de devolución de llamada

289

Estoy tratando de pasar algún parámetro a una función utilizada como devolución de llamada, ¿cómo puedo hacer eso?

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

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

callbackTester (tryMe, "hello", "goodbye");
vitto
fuente
99
Lo que estás haciendo debería funcionar. Que problemas tienes
Daniel Vassallo
1
Su código funciona bien, ¿cuál es el problema?
Sarfraz
1
Debería funcionar ... jsfiddle.net/QXQZj
Hristo
lo siento, fue mi culpa en la sintaxis del código principal, pensé que era esto porque esta es la primera vez que uso una devolución de llamada en JavaScript
vitto
Si desea agregar parámetros a una devolución de llamada pero no puede cambiar lo que lo está llamando (ya que no tiene poder para cambiar el orden de los argumentos, puede vincular previamente algunos de los parámetros de devolución de llamada con enlace JS, como he mostrado en esta respuesta: stackoverflow.com/a/28120741/1695680
ThorSummoner

Respuestas:

253

Si desea algo un poco más general, puede usar la variable de argumentos de esta manera:

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

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

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

Pero de lo contrario, su ejemplo funciona bien (los argumentos [0] se pueden usar en lugar de la devolución de llamada en el probador)

Simon Scarfe
fuente
53
Mientras estemos en el espíritu de ser generales, callback.apply(arguments)ya que el cuerpo de la función callbackTesteres extensible más allá del escenario de dos argumentos.
Steven
1
lo siento, fue un error de sintaxis en el código principal, pensé que era esto porque es la primera vez que uso una devolución de llamada en JavaScript, me ayudaron a comprender que no era el problema y a ver un gran ejemplo.
vitto
3
Para su información, el uso de una función anónima (respuesta de Marimuthu) o .bind () (respuesta de Andy) son formas mucho más claras de pasar argumentos a una devolución de llamada.
antoine
203

Esto también funcionaría:

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

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

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

Otro escenario:

// 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); 
}); 
Marimuthu Madasamy
fuente
2
Esto funciona muy bien porque también permite que la función anónima pase parámetros como este: callbackTester (function (data) {tryMe (data, "hello", "goodbye");});
Michael Khalili
También me gusta comprobar que la devolución de llamada es, de hecho, una función. if (typeof window[callback] == 'function') window[callback].call(this);
GreeKatrina
63

Tu pregunta no está clara. Si está preguntando cómo puede hacer esto de una manera más simple, debería echar un vistazo al método ECMAScript 5th edition .bind () , que es miembro de Function.prototype . Al usarlo, puedes hacer algo como esto:

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

function callbackTester (callback) {
    callback();
}

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

También puede usar el siguiente código, que agrega el método si no está disponible en el navegador actual:

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

Ejemplo

bind () - Documentación PrototypeJS

Andy E
fuente
Por interés, ¿cuál es la diferencia entre Array.prototype.slice.call(arguments)y arguments.slice()?
sje397
77
@ sje397: los argumentos no son una matriz * real *, por lo que no tiene un método slice () . Sin embargo, el método slice () en el prototipo Array. es intencionalmente genérico, por lo que puede pasar cualquier objeto que tenga índices numéricos y una propiedad de longitud y funcionará.
Andy E
2
Esta es la respuesta más elegante
antoine
Este .bind () es realmente genial y extiende mucho el uso y la simplicidad de las devoluciones de llamada. Como muestra básica para entenderlo, si tiene:f = function(arg1,arg2){alert(arg1+arg2);}.bind(this,"abc"); f("def") // Gives "abcdef"
Le Droid
Esta es realmente una respuesta grt. Impresionante y funciona bien para mí. Gracias :)
Vishnu Mishra
13

Cuando tiene una devolución de llamada que será llamada por algo diferente a su código con un número específico de parámetros y desea pasar parámetros adicionales, puede pasar una función de contenedor como la devolución de llamada y dentro del contenedor pasar los parámetros adicionales.

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
}
Blake Mills
fuente
9

Si no está seguro de cuántos parámetros pasará a las funciones de devolución de llamada, use applyfunction.

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

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

callbackTester(tryMe,['hello','goodbye']);
Zeeman Chen
fuente
4

Envuelva las funciones 'secundarias' que se pasan como / con argumentos dentro de los contenedores de funciones para evitar que se evalúen cuando se llama a la función 'principal'.

function outcome(){
    return false;
}

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

process(function(){alert("OKAY");},function(){alert("OOPS");})
Alan McCune
fuente
4

Código de una pregunta con cualquier número de parámetros y un contexto de devolución de llamada:

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
Adam Skobodzinski
fuente
2

Use la función curry como en este simple ejemplo.

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>


fuente
0

Una nueva versión para el escenario en el que alguna otra función invocará la devolución de llamada, no su propio código, y desea agregar parámetros adicionales.

Por ejemplo, supongamos que tiene muchas llamadas anidadas con devoluciones de llamada correctas y erróneas. Usaré promesas angulares para este ejemplo, pero cualquier código de JavaScript con devoluciones de llamada sería el mismo para ese propósito.

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

Ahora es posible que desee ordenar su código definiendo una función para registrar errores, manteniendo el origen del error para fines de depuración. Así es como procedería a refactorizar su código:

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 función de llamada aún agregará el parámetro de error después de los parámetros de la función de devolución de llamada.

Juangui Jordán
fuente
0

Estaba buscando lo mismo y terminé con la solución y aquí es un ejemplo simple si alguien quiere pasar por esto.

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

También publicado en la otra pregunta aquí

Code_Crash
fuente
0

Permíteme darte un ejemplo de estilo Node.js muy simple de usar una devolución de llamada:

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

y el HTML que representará el resultado:

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

Puede jugar con él aquí: https://jsfiddle.net/q8gnvcts/ , por ejemplo, intente pasar una cadena en lugar del número: myTest ('alguna cadena', 6, función (err, resultado) ... y vea el resultado.

Espero que este ejemplo ayude porque representa la idea muy básica de las funciones de devolución de llamada.

Vlado
fuente
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");

Lea más sobre la sintaxis de propagación

Dmitry Grinko
fuente
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); 
                    }
                });
Santhos Jery
fuente
1
Agregue una explicación de lo que está haciendo y por qué :)
Preston Badeer
Bien, lo haré desde mi próxima respuesta, perdón por lo anterior porque esta es mi primera respuesta.
Santhos Jery el