¿Pasar una función con parámetros como parámetro?

151

¿Es posible pasar una función de JavaScript con parámetros como parámetro?

Ejemplo:

$(edit_link).click( changeViewMode( myvar ) );
Lucia
fuente
55
Parece JQuery, y muy probablemente lo es, pero eso es irrelevante. El uso o los parámetros y funciones son los mismos independientemente de las bibliotecas de Javascript que use.
Guffa
@Guffa - Me preguntaba si debería etiquetarse con jQuery
Russ Cam
1
@Lucia Por favor considere cambiar la respuesta aceptada a esto .
Michał Perłakowski
Si está trabajando con React, considere stackoverflow.com/questions/41369497/…
Michael Freidgeim

Respuestas:

244

Use un "cierre":

$(edit_link).click(function(){ return changeViewMode(myvar); });

Esto crea un contenedor de funciones temporal anónimo que conoce el parámetro y lo pasa a la implementación real de devolución de llamada.

Fernando Beyer
fuente
3
Si desea llamar a una función en un objeto, debe llamar a bind (). myObj.click (function () {this.doSomething ();} .bind (myObj)); Eso hará que "esto" sea myObj.
Eli
1
¿No es este un problema de rendimiento cuando se trata con muchos de estos? Por ejemplo, estás renderizando un onPress en una fila y tienes 10,000 filas. Esto crea un nuevo contenedor de función temporal anónimo para cada fila. ¿Hay alguna otra forma de hacerlo?
Joshua Pinter el
@JoshuaPinter La técnica en sí no es un problema. Si necesita la misma función llamar 10,000 veces, simplemente puede guardar el contenedor en una variable, de modo que lo cree solo una vez. Si necesita pasar 10,000 contextos diferentes, hay poco que pueda hacer. Tenga cuidado con la optimización prematura: como siempre con el rendimiento, debe medir para ver si hay un problema o no. Los motores de JavaScript actuales son muy potentes y pueden optimizar el código de formas sorprendentes.
Ferdinand Beyer
@FerdinandBeyer Impresionante, gracias por el consejo. Un amigo me dijo que era una mala práctica y que, en cambio, debería usarlo this.myFunction = this.myFunction.bind(this)en su constructormétodo. Pero, como dijiste, cuando tienes que pasar diferentes contextos para cada uno, como todas las filas diferentes en las que haces clic para abrir la página de detalles de esa fila, no es evitable.
Joshua Pinter
@FerdinandBeyer, digamos que myvar es una cadena y se cambia entre dos invocaciones consecutivas de pasar changeViewMode como un cierre, pero changeViewMode siempre recibe el primer valor de myvar, quiero llamar a la función de cierre con un valor de argumento diferente asignado a la misma variable myvar,
nmxprime
42

Uso Function.prototype.bind(). Citando a MDN:

El bind()método crea una nueva función que, cuando se llama, tiene su thispalabra clave establecida en el valor proporcionado, con una secuencia dada de argumentos que precede a cualquier proporcionado cuando se llama a la nueva función.

Es compatible con todos los principales navegadores, incluido IE9 +.

Su código debería verse así:

$(edit_link).click(changeViewMode.bind(null, myvar));

Nota al margen: supongo que está en un contexto global, es decir, la thisvariable es window; de lo contrario, use en thislugar de null.

Michał Perłakowski
fuente
Gracias, esto me ayudó. Lo usé así:$.ajax(url).done(handler.bind(this, var1, var2));
Thomas
2
¿Qué opción es la mejor? ¿Usando cierre o usando la función de enlace? Avíseme si hay algún impacto en el rendimiento
Varun
55
@Varun See ¿Por qué el enlace es más lento que un cierre?
Michał Perłakowski
15

No, pero puede pasar uno sin parámetros y hacer esto:

$(edit_link).click(
  function() { changeViewMode(myvar); }
);

Entonces, pasa una función anónima sin parámetros, esa función llama a su función parametrizada con la variable en el cierre

Clyde
fuente
8

Sí, así:

$(edit_link).click(function() { changeViewMode(myvar) });
Philippe Leybaert
fuente
7

O si está utilizando es6, debería poder utilizar una función de flecha

$(edit_link).click(() => changeViewMode(myvar));
Christian Bartram
fuente
2

Puedes hacerlo

var message  = 'Hello World';

var callback = function(){
alert(this)
}.bind(message);

y entonces

function activate(callback){
  callback && callback();
}

activate(callback);

O si su devolución de llamada contiene una lógica más flexible, puede pasar el objeto.

Manifestación

Alexandr Sargsyan
fuente
2

Este es un ejemplo siguiendo el enfoque de Ferdinand Beyer:

function function1()
{
    function2(function () { function3("parameter value"); });
}
function function2(functionToBindOnClick)
{
    $(".myButton").click(functionToBindOnClick);
}
function function3(message) { alert(message); }

En este ejemplo, el "valor del parámetro" se pasa de la función1 a la función3 a través de la función2 utilizando un ajuste de función.

erionpc
fuente