Passando uma função com parâmetros como parâmetro?

151

É possível passar uma função javascript com parâmetros como parâmetro?

Exemplo:

$(edit_link).click( changeViewMode( myvar ) );
Lucia
fonte
5
Parece JQuery, e provavelmente é, mas isso é irrelevante. O uso ou parâmetros e funções são os mesmos, independentemente de quais bibliotecas Javascript você usa.
Guffa
@Guffa - Eu queria saber se ele deve ser marcado com jQuery
Russ Cam
1
@ Lucia Por favor, considere alterar a resposta aceita para isso .
Michał Perłakowski 26/02
Se você estiver trabalhando com o React, considere stackoverflow.com/questions/41369497/…
Michael Freidgeim

Respostas:

244

Use um "fechamento":

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

Isso cria um invólucro de função temporária anônima que conhece o parâmetro e o passa para a implementação de retorno de chamada real.

Ferdinand Beyer
fonte
3
Se você deseja chamar uma função em um objeto, precisa chamar bind (). myObj.click (function () {this.doSomething ();} .bind (myObj)); Isso fará com que "isto" seja myObj.
Eli #
1
Isso não é um problema de desempenho ao lidar com muitos deles? Por exemplo, você está renderizando um onPress em uma linha e possui 10.000 linhas. Isso cria um novo invólucro de função temporária anônima para cada linha. Existe alguma outra maneira de fazer isso?
Joshua Pinter
@ JoshuaPinter A técnica em si não é um problema. Se você precisar da mesma chamada de função 10.000 vezes, poderá simplesmente salvar o wrapper em uma variável, para criá-lo apenas uma vez. Se você precisar passar por 10.000 contextos diferentes, pouco poderá fazer. Cuidado com a otimização prematura: como sempre com o desempenho, você precisa medir para ver se há um problema ou não. Os mecanismos JavaScript de hoje são muito poderosos e podem otimizar o código de maneiras surpreendentes.
Ferdinand Beyer
@FerdinandBeyer Incrível, obrigado pela dica. Um amigo me disse que era uma prática ruim e que você deveria usar this.myFunction = this.myFunction.bind(this)no seu constructormétodo. Mas, como você disse, quando você precisa passar contextos diferentes para cada um deles, como todas as linhas diferentes nas quais você clica para abrir a página de detalhes dessa linha, não é evitável.
Joshua Pinter
@FerdinandBeyer, digamos que myvar é uma string e foi alterada entre duas invocações consecutivas de passar changeViewMode como um fechamento, mas changeViewMode sempre recebe o primeiro valor de myvar, quero chamar a função de fechamento com um valor de argumento diferente atribuído à mesma variável myvar,
nmxprime 18/07/19
42

Use Function.prototype.bind(). Citando MDN:

O bind()método cria uma nova função que, quando chamada, tem sua thispalavra-chave definida como o valor fornecido, com uma sequência de argumentos fornecida antes de qualquer fornecida quando a nova função é chamada.

É suportado por todos os principais navegadores, incluindo o IE9 +.

Seu código deve ficar assim:

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

Nota lateral: Presumo que você esteja no contexto global, ou seja, thisvariável é window; caso contrário, use em thisvez de null.

Michał Perłakowski
fonte
Obrigado, isso me ajudou. Usou-o assim:$.ajax(url).done(handler.bind(this, var1, var2));
Thomas
2
Qual opção é a melhor? Usando encerramento ou usando a função de ligação? Por favor, deixe-me saber se há algum impacto no desempenho
Varun
5
@Varun See Por que o bind é mais lento que o fechamento?
Michał Perłakowski
15

Não, mas você pode passar um sem parâmetros e faça o seguinte:

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

Então você está passando uma função anônima sem parâmetros, essa função chama sua função parametrizada com a variável no fechamento

Clyde
fonte
8

Sim como isso:

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

Ou, se você estiver usando es6, poderá usar uma função de seta

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

Você consegue fazer isso

var message  = 'Hello World';

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

e depois

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

activate(callback);

Ou, se o seu retorno de chamada contiver uma lógica mais flexível, você poderá passar o objeto.

Demo

Alexandr Sargsyan
fonte
2

Este é um exemplo da abordagem de Ferdinand Beyer:

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

Neste exemplo, o "valor do parâmetro" é passado da função1 para a função3 através da função2 usando uma quebra de função.

erionpc
fonte