Przekaż funkcję JavaScript jako parametr

665

Jak przekazać funkcję jako parametr bez wykonywania funkcji w funkcji nadrzędnej lub używania eval()? (Odkąd przeczytałem, że to niepewne.)

Mam to:

addContact(entityId, refreshContactList());

Działa, ale problem polega na tym, że refreshContactListuruchamia się, gdy funkcja jest wywoływana, a nie wtedy, gdy jest używana w funkcji.

Mógłbym to obejść za pomocą eval(), ale zgodnie z tym, co przeczytałem, nie jest to najlepsza praktyka. Jak mogę przekazać funkcję jako parametr w JavaScript?

imperium2335
źródło

Odpowiedzi:

930

Wystarczy usunąć nawias:

addContact(entityId, refreshContactList);

Następnie przekazuje funkcję bez uprzedniego jej wykonania.

Oto przykład:

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

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

addContact(1, refreshContactList);
Fenton
źródło
6
@stevefenton, rozważ zaktualizowanie swojej odpowiedzi za pomocą komentarza h2ooooooo, byłoby to bardzo przydatne.
Morgan Wilde,
5
Na podstawie pytania funkcja zwrotna nie akceptuje parametrów, dlatego pominąłem je w przykładzie. Dodam komentarz na ten temat.
Fenton,
4
@Veverke Wyglądałoby to tak ...addContact(1, function(id) { console.log(id); });
Fenton
4
@ Steve Fenton: po przeczytaniu odpowiedzi zadałem sobie pytanie, dlaczego zapytałem ... :-)
Veverke,
1
Składnia klasy w ECMAScript nie miałaby =znaku ... class myFuncs {zamiast tego class myFuncs = {. Będziesz także musiał działać w środowisku, które obsługiwało składnię klas (jeszcze nie wszystkie przeglądarki ją obsługują). Jeśli nadal masz problemy, może lepiej pasować do zupełnie nowego pytania, ponieważ twoim problemem nie jest przekazywanie funkcji - jest to ogólna składnia ES.
Fenton,
337

Jeśli chcesz przekazać funkcję, po prostu odwołaj się do niej po nazwie bez nawiasów:

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

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

Ale czasami możesz chcieć przekazać funkcję z dołączonymi argumentami , ale nie wywoływać jej dopóki nie zostanie wywołane wywołanie zwrotne. Aby to zrobić, wywołując go, po prostu zawiń w anonimową funkcję, taką jak ta:

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

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

Jeśli wolisz, możesz również użyć funkcji Apply i mieć trzeci parametr, który jest tablicą argumentów, na przykład:

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"]); 
Dallin
źródło
70
powinno to zostać ocenione wyżej, ponieważ zajmuje się także przekazywaniem funkcji za pomocą argumentów
deltanine
3
Dodam do tego, że sama ta funkcja - możliwość przekazywania funkcji JavaScript jako argumentów, zmiennych lub tym podobnych - jest funkcją, która sprawia, że ​​JavaScript jest tak potężny i świetny do kodowania.
TheHansinator
@ Compynerd255 Zgadzam się, to i umiejętność szybkiego tworzenia literałów obiektowych to moje dwa ulubione aspekty Javascript. Zawsze brakuje mi literałów obiektowych w językach, które ich nie mają.
dallin,
3
Jestem bardzo wdzięczny Javascriptowi za udostępnienie tej funkcji, a Tobie @Dallin za poinformowanie mnie o jej istnieniu.
Dipendu Paul,
Na przykład „zawiń w funkcję anonimową”, jeśli nie jest to oczywiste, funkcja anonimowa zwraca samą funkcję (z parametrami) i jest wywoływana, gdy osiągnie nawias w func (). Zajęło mi to trochę czasu, aby zrozumieć, więc pomyślałem, że może to pomóc innym.
hubpixel
51

Przykład 1:

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

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

Przykład 2:

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

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

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

Spójrz na to

Gadde
źródło
w pierwszym przykładzie powinieneś dodać słowo kluczowe return, takie jak: function funk (a, foo) {return foo (a) // to zwróci a} w przeciwnym razie zostanie niezdefiniowany
Artem Fedotov
34

Aby przekazać funkcję jako parametr, wystarczy usunąć nawiasy!

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

Chodzi o to, że funkcja jest dość podobna do zmiennej. Zamiast pisać

function ToBeCalled() { /* something */ }

równie dobrze możesz pisać

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

Między nimi są niewielkie różnice, ale i tak - oba są prawidłowymi sposobami definiowania funkcji. Teraz, jeśli zdefiniujesz funkcję i wyraźnie przypiszesz ją do zmiennej, wydaje się całkiem logiczne, że możesz przekazać ją jako parametr do innej funkcji i nie potrzebujesz nawiasów:

anotherFunction(ToBeCalledVariable);
naiwiści
źródło
2
Wystarczy typeof paramFunc == "function", bo jeśli nie można go wywołać, możesz go zignorować.
Jimmy Knoot,
16

Wśród programistów JavaScript jest takie zdanie: „Eval is Evil”, więc staraj się go unikać za wszelką cenę!

Oprócz odpowiedzi Steve'a Fentona możesz także przekazywać funkcje bezpośrednio.

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

function callAddContact() {
    addContact("entity", function() { DoThis(); });
}
Matthew Layton
źródło
8

Odciąłem wszystkie moje włosy tym problemem. Nie mogłem sprawić, by powyższe przykłady działały, więc skończyłem jak:

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

I to działa jak urok ... przynajmniej na to, czego potrzebowałem. Mam nadzieję, że to może pomóc.

Fenix ​​Aoras
źródło
6

Proponuję umieścić parametry w tablicy, a następnie podzielić je za pomocą .apply()funkcji. Teraz możemy łatwo przekazać funkcję z wieloma parametrami i wykonać ją w prosty sposób.

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
Naramsim
źródło
5

Możesz także użyć eval()tego samego.

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

Otóż ​​to. Szukałem również tego rozwiązania i wypróbowałem rozwiązania podane w innych odpowiedziach, ale w końcu udało mi się to z powyższego przykładu.

NullPointer
źródło
2

Oto inne podejście:

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

a('Hello',function(e){alert(e+ ' world!');}); //=> Hello world     
Cochon
źródło
2

W rzeczywistości wydaje się to trochę skomplikowane, nie jest.

pobierz metodę jako parametr:

 function JS_method(_callBack) { 

           _callBack("called");  

        }

Możesz podać jako metodę parametru:

    JS_method(function (d) {
           //Finally this will work.
           alert(d)
    });
Hakkı Eser
źródło
1
Proszę wyjaśnić swoją odpowiedź.
MillaresRoo
2

Pozostałe odpowiedzi doskonale opisują, co się dzieje, ale jedną ważną „gotcha” jest upewnienie się, że wszystko, co przechodzi, jest rzeczywiście odniesieniem do funkcji.

Na przykład, jeśli przejdziesz przez ciąg zamiast funkcji, otrzymasz błąd:

function function1(my_function_parameter){
    my_function_parameter();   
}

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

function1(function2); //This will work

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

Zobacz JsFiddle

Zwycięzca
źródło
0

Kiedyś musisz poradzić sobie z obsługą zdarzeń, więc musisz przekazać zdarzenie jako argument, większość współczesnej biblioteki reaguje, angular może tego potrzebować.

Muszę zastąpić funkcję OnSubmit (funkcję z biblioteki innej firmy) za pomocą niestandardowego sprawdzania poprawności w reakjs i przekazałem funkcję i zdarzenie, jak poniżej

PIERWOTNIE

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

STWORZYŁA Nową FUNKCJĘ uploadi onSubmitjako argumenty wywołała pass i event

<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);
}
sumit
źródło
-3

Możesz także użyć JSON do przechowywania i wysyłania funkcji JS.

Sprawdź następujące:

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



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

Spowoduje to wydrukowanie „a”.

Poniższe ma taki sam efekt z powyższym:

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

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

function main(){
    myFunc2(myFunc1);
}

Który ma również ten sam efekt z następującymi:

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


function myFunc2 (functionParameter){
    functionParameter();
}

function main(){
    myFunc2(myFunc1);
}

I paradygmat obiektu wykorzystujący klasę jako prototyp obiektu:

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

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


function main(){    
    var myClass = new Class();  
    myClass.myFunc2(myClass.myFunc1);
}
gazgas
źródło
9
Przykład twojego najlepszego kodu to nie JSON. To jest standardowy obiekt JavaScript. Nie można także wysyłać / odbierać funkcji w JSON.
Matthew Layton