Pase una función de JavaScript como parámetro


665

¿Cómo paso una función como parámetro sin que la función se ejecute en la función "principal" o se use eval()? (Desde que leí que es inseguro).

Tengo esto:

addContact(entityId, refreshContactList());

Funciona, pero el problema es que se refreshContactListdispara cuando se llama a la función, en lugar de cuando se usa en la función.

Podría eval()evitarlo usando , pero no es la mejor práctica, según lo que he leído. ¿Cómo puedo pasar una función como parámetro en JavaScript?

Respuestas:


930

Solo necesita eliminar el paréntesis:

addContact(entityId, refreshContactList);

Esto luego pasa la función sin ejecutarla primero.

Aquí hay un ejemplo:

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

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

addContact(1, refreshContactList);

66
@stevefenton, considera actualizar tu respuesta con un comentario h2ooooooo, sería muy útil.
Morgan Wilde

55
Según la pregunta, la devolución de llamada no acepta parámetros, por lo que los he dejado fuera del ejemplo. Agregaré un comentario al respecto.
Fenton

44
@Veverke Se vería así ...addContact(1, function(id) { console.log(id); });
Fenton

44
@ Steve Fenton: después de leer su respuesta, me pregunté por qué pregunté ... :-)
Veverke

1
La sintaxis de clase en ECMAScript no tendría un =signo ... en class myFuncs {lugar de class myFuncs = {. También necesitaría ejecutarse en un entorno que admitiera la sintaxis de la clase (no todos los navegadores lo admiten todavía). Si todavía tiene dificultades, podría ser más adecuado para una pregunta completamente nueva, ya que su problema no es sobre pasar funciones, es la sintaxis general de ES.
Fenton

338

Si desea pasar una función, simplemente haga referencia a ella por su nombre sin los paréntesis:

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

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

Pero a veces es posible que desee pasar una función con argumentos incluidos , pero que no se llame hasta que se invoque la devolución de llamada. Para hacer esto, cuando lo llame, simplemente envuélvalo en una función anónima, como esta:

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

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

Si lo prefiere, también puede usar la función de aplicación y tener un tercer parámetro que es una matriz de argumentos, como los siguientes:

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
esto debería clasificarse más alto ya que también aborda cómo pasar una función con argumentos
deltanine

3
Y algo que voy a añadir a esto es que esta característica por sí sola - ser capaz de pasar funciones de JavaScript como argumentos o variables o similar - es la característica que hace que JavaScript tan poderoso y tan grande que el código en.
TheHansinator

@ Compynerd255 Estoy de acuerdo, esto y la capacidad de crear rápidamente literales de objetos son mis dos aspectos favoritos de Javascript. Siempre extraño los literales de objetos en idiomas que no los tienen.
dallin

3
Estoy muy agradecido con Javascript por proporcionar esta función y por usted @dallin por hacerme saber que existe.
Dipendu Paul

Para el ejemplo "envolverlo en una función anónima", en caso de que no sea obvio, la función anónima devuelve la función en sí (con parámetros) y se invoca cuando llega al paréntesis en func (). Me tomó un tiempo darme cuenta, así que pensé que podría ayudar a otros.
hubpixel

51

Ejemplo 1:

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

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

Ejemplo 2

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

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

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

mira esto


en el primer ejemplo, debe agregar la palabra clave return, así: function funct (a, foo) {return foo (a) // esto devolverá a} de lo contrario quedará indefinido
Artem Fedotov

34

Para pasar la función como parámetro, simplemente elimine los corchetes.

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

La idea detrás de esto es que una función es bastante similar a una variable. En lugar de escribir

function ToBeCalled() { /* something */ }

bien podrías escribir

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

Hay diferencias menores entre los dos, pero de todos modos, ambos son formas válidas de definir una función. Ahora, si define una función y la asigna explícitamente a una variable, parece bastante lógico que pueda pasarla como parámetro a otra función y no necesite corchetes:

anotherFunction(ToBeCalledVariable);

2
Simplemente typeof paramFunc == "function"es suficiente, porque si no es invocable, puede ignorarlo.
Jimmy Knoot

16

Hay una frase entre los programadores de JavaScript: "Eval is Evil", ¡así que trata de evitarlo a toda costa!

Además de la respuesta de Steve Fenton, también puede pasar funciones directamente.

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

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

8

Me corté todo el cabello con ese problema. No pude hacer que los ejemplos anteriores funcionaran, así que terminé como:

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

Y eso funciona a las mil maravillas ... al menos para lo que necesitaba. Espero que pueda ayudar a algunos.


6

Sugiero poner los parámetros en una matriz y luego dividirlos usando la .apply()función. Así que ahora podemos pasar fácilmente una función con muchos parámetros y ejecutarla de una manera 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

5

También puedes usar eval()para hacer lo mismo.

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

Eso es. También estaba buscando esta solución y probé soluciones proporcionadas en otras respuestas, pero finalmente conseguí que funcionara con el ejemplo anterior.


2

Aquí hay otro enfoque:

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

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

2

De hecho, parece un poco complicado, no lo es.

obtener método como parámetro:

 function JS_method(_callBack) { 

           _callBack("called");  

        }

Puedes dar como método de parámetro:

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

1
Por favor, explique su respuesta.
MillaresRoo

2

Las otras respuestas hacen un excelente trabajo al describir lo que está sucediendo, pero un "problema" importante es asegurarse de que lo que sea que pase sea una referencia a una función.

Por ejemplo, si pasa a través de una cadena en lugar de una función, obtendrá un error:

function function1(my_function_parameter){
    my_function_parameter();   
}

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

function1(function2); //This will work

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

Ver JsFiddle


0

En algún momento, cuando necesite lidiar con el controlador de eventos, también debe pasar el evento como argumento, la mayoría de la biblioteca moderna, como reaccionar, angular, podría necesitar esto.

Necesito anular la función OnSubmit (función de la biblioteca de terceros) con alguna validación personalizada en reactjs y pasé la función y el evento tanto como a continuación

ORIGINALMENTE

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

HECHO UNA NUEVA FUNCIÓN uploady llamado pasado onSubmity evento como argumentos

<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

También puede usar un JSON para almacenar y enviar funciones JS.

Verifique lo siguiente:

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



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

Esto imprimirá 'a'.

Lo siguiente tiene el mismo efecto con lo anterior:

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

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

function main(){
    myFunc2(myFunc1);
}

Lo que también tiene el mismo efecto con lo siguiente:

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


function myFunc2 (functionParameter){
    functionParameter();
}

function main(){
    myFunc2(myFunc1);
}

Y un paradigma de objeto que usa Class como objeto prototipo:

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

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


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

99
Su ejemplo de código superior no es JSON. Este es un objeto JavaScript estándar. Tampoco puede enviar / recibir funciones en JSON.
Matthew Layton el
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.