Przekazywanie funkcji z parametrami jako parametrem?

151

Czy można przekazać funkcję javascript z parametrami jako parametrem?

Przykład:

$(edit_link).click( changeViewMode( myvar ) );
Lucia
źródło
5
Wygląda jak JQuery i najprawdopodobniej tak, ale to nie ma znaczenia. Użycie lub parametry i funkcje są takie same, niezależnie od używanych bibliotek JavaScript.
Guffa,
@Guffa - zastanawiałem się, czy powinien być oznaczony tagiem jQuery
Russ Cam
1
@Lucia Proszę rozważyć zmianę zaakceptowanej odpowiedzi na to .
Michał Perłakowski
Jeśli pracujesz z Reactem, rozważ stackoverflow.com/questions/41369497/ ...
Michael Freidgeim

Odpowiedzi:

244

Użyj „zamknięcia”:

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

Tworzy to anonimowe opakowanie funkcji tymczasowej, które wie o parametrze i przekazuje go do rzeczywistej implementacji wywołania zwrotnego.

Ferdinand Beyer
źródło
3
Jeśli chcesz wywołać funkcję na obiekcie, musisz wywołać bind (). myObj.click (function () {this.doSomething ();} .bind (myObj)); Dzięki temu „this” będzie myObj.
Eli
1
Czy nie jest to problem z wydajnością, gdy mamy do czynienia z wieloma z nich? Np. Renderujesz onPress w rzędzie i masz 10000 wierszy. Spowoduje to utworzenie nowego anonimowego opakowania funkcji tymczasowej dla każdego wiersza. Czy jest inny sposób, aby to zrobić?
Joshua Pinter
@JoshuaPinter Sama technika nie jest problemem. Jeśli potrzebujesz tej samej funkcji wywołać 10000 razy, możesz po prostu zapisać opakowanie w zmiennej, aby utworzyć ją tylko raz. Jeśli chcesz przekazać 10000 różnych kontekstów, niewiele możesz zrobić. Uważaj na przedwczesną optymalizację: jak zawsze w przypadku wydajności, musisz zmierzyć, czy jest problem, czy nie. Dzisiejsze silniki JavaScript są bardzo wydajne i mogą optymalizować kod w zaskakujący sposób.
Ferdinand Beyer
@FerdinandBeyer Niesamowite, dzięki za cynk. Znajomy powiedział mi, że to zła praktyka i że powinieneś zamiast tego użyć this.myFunction = this.myFunction.bind(this)w swojej constructormetodzie. Ale, jak powiedziałeś, kiedy musisz przekazać do niego różne konteksty dla każdego z nich, na przykład wszystkie różne wiersze, które klikasz, aby otworzyć stronę szczegółów tego wiersza, nie można tego uniknąć.
Joshua Pinter
@FerdinandBeyer, powiedzmy, że myvar jest ciągiem i jest zmieniany między dwoma kolejnymi wywołaniami przekazania changeViewMode jako zamknięcia, ale changeViewMode zawsze otrzymuje pierwszą wartość myvar, chcę wywołać funkcję zamknięcia z inną wartością argumentu przypisaną do tej samej zmiennej myvar,
nmxprime
42

Użyj Function.prototype.bind(). Cytując MDN:

bind()Metoda tworzy nową funkcję, która, kiedy nazywa, ma swój thiszestaw słów kluczowych do podanej wartości z danej sekwencji argumentów poprzedzających każdy pod warunkiem, że nowa funkcja jest wywoływana.

Jest obsługiwany przez wszystkie główne przeglądarki, w tym IE9 +.

Twój kod powinien wyglądać następująco:

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

Uwaga dodatkowa: zakładam, że jesteś w kontekście globalnym, tj. thisZmienna jest window; w przeciwnym razie użyj thiszamiast null.

Michał Perłakowski
źródło
Dzięki, to mi pomogło. Użyłem tego w ten sposób:$.ajax(url).done(handler.bind(this, var1, var2));
Thomas
2
Która opcja jest najlepsza? Używasz zamknięcia lub funkcji bind? Daj mi znać, jeśli ma to jakiś wpływ na wydajność
Varun,
5
@Varun Zobacz Dlaczego
Michał Perłakowski
15

Nie, ale możesz przekazać jeden bez parametrów i zrobić to:

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

Więc przekazujesz anonimową funkcję bez parametrów, która następnie wywołuje sparametryzowaną funkcję ze zmienną w zamknięciu

Clyde
źródło
8

Tak, tak:

$(edit_link).click(function() { changeViewMode(myvar) });
Philippe Leybaert
źródło
7

Lub jeśli używasz es6, powinieneś być w stanie użyć funkcji strzałki

$(edit_link).click(() => changeViewMode(myvar));
Christian Bartram
źródło
2

Możesz to zrobić

var message  = 'Hello World';

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

i wtedy

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

activate(callback);

Lub jeśli twój callback zawiera bardziej elastyczną logikę, możesz przekazać obiekt.

Próbny

Alexandr Sargsyan
źródło
2

Oto przykład zgodny z podejściem Ferdinanda Beyera:

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

W tym przykładzie „wartość parametru” jest przekazywana z funkcji 1 do funkcji 3 poprzez funkcję 2 przy użyciu zawijania funkcji.

erionpc
źródło