JavaScript: Przekazywanie parametrów do funkcji zwrotnej

289

Próbuję przekazać jakiś parametr do funkcji używanej jako wywołanie zwrotne, jak mogę to zrobić?

function tryMe (param1, param2) {
    alert (param1 + " and " + param2);
}

function callbackTester (callback, param1, param2) {
    callback (param1, param2);
}

callbackTester (tryMe, "hello", "goodbye");
witam
źródło
9
To, co robisz, powinno działać. Jakie masz problemy?
Daniel Vassallo,
1
Twój kod działa dobrze, na czym polega problem?
Sarfraz,
1
Powinno działać ... jsfiddle.net/QXQZj
Hristo
przepraszam, to była moja wina w głównej składni kodu, pomyślałem, że to dlatego, że po raz pierwszy używam wywołania zwrotnego w JavaScript
vitto
Jeśli chcesz dodać parametry do wywołania zwrotnego, ale nie możesz zmienić tego, co go wywołuje (ponieważ nie masz uprawnień do zmiany kolejności argumentów, możesz wstępnie powiązać niektóre parametry wywołania zwrotnego za pomocą JS bind, jak pokazano na ta odpowiedź: stackoverflow.com/a/28120741/1695680
ThorSummoner

Odpowiedzi:

253

Jeśli chcesz czegoś nieco bardziej ogólnego, możesz użyć zmiennej arguments w następujący sposób:

function tryMe (param1, param2) {
    alert(param1 + " and " + param2);
}

function callbackTester (callback) {
    callback (arguments[1], arguments[2]);
}

callbackTester (tryMe, "hello", "goodbye");

Ale w przeciwnym razie twój przykład działa dobrze (argumenty [0] mogą być użyte zamiast wywołania zwrotnego w testerze)

Simon Scarfe
źródło
53
Tak długo, jak jesteśmy w duchu bycia generałem, callback.apply(arguments)ponieważ ciało funkcji dla callbackTesterjest rozszerzalne poza scenariusz dwóch argumentów.
Steven,
1
przepraszam, to był błąd składniowy w głównym kodzie, myślałem, że to dlatego, że po raz pierwszy używam wywołania zwrotnego w JavaScript, pomogłeś mi zrozumieć, że to nie problem, i zobaczyć świetny przykład.
vitto
3
Do Twojej wiadomości, użycie anonimowej funkcji (odpowiedź Marimuthu) lub .bind () (odpowiedź Andy'ego) to znacznie prostsze sposoby przekazywania argumentów do wywołania zwrotnego.
antoine
203

Działa to również:

// callback function
function tryMe (param1, param2) { 
    alert (param1 + " and " + param2); 
} 

// callback executer 
function callbackTester (callback) { 
    callback(); 
} 

// test function
callbackTester (function() {
    tryMe("hello", "goodbye"); 
}); 

Kolejny scenariusz:

// callback function
function tryMe (param1, param2, param3) { 
    alert (param1 + " and " + param2 + " " + param3); 
} 

// callback executer 
function callbackTester (callback) { 
//this is the more obivous scenario as we use callback function
//only when we have some missing value
//get this data from ajax or compute
var extraParam = "this data was missing" ;

//call the callback when we have the data
    callback(extraParam); 
} 

// test function
callbackTester (function(k) {
    tryMe("hello", "goodbye", k); 
}); 
Marimuthu Madasamy
źródło
2
Działa to świetnie, ponieważ umożliwia również anonimowej funkcji przekazywanie parametrów takich jak: callbackTester (function (data) {tryMe (data, „hello”, „goodbye”);});
Michael Khalili
Chciałbym również sprawdzić, czy funkcja zwrotna jest w rzeczywistości funkcją. if (typeof window[callback] == 'function') window[callback].call(this);
GreeKatrina
63

Twoje pytanie jest niejasne. Jeśli zastanawiasz się, jak to zrobić w prostszy sposób, zapoznaj się z metodą ECMAScript 5. edycji .bind () , która jest członkiem Function.prototype . Korzystając z niego, możesz zrobić coś takiego:

function tryMe (param1, param2) {
    alert (param1 + " and " + param2);
}

function callbackTester (callback) {
    callback();
}

callbackTester(tryMe.bind(null, "hello", "goodbye"));

Możesz także użyć następującego kodu, który dodaje metodę, jeśli nie jest dostępna w bieżącej przeglądarce:

// From Prototype.js
if (!Function.prototype.bind) { // check if native implementation available
  Function.prototype.bind = function(){ 
    var fn = this, args = Array.prototype.slice.call(arguments),
        object = args.shift(); 
    return function(){ 
      return fn.apply(object, 
        args.concat(Array.prototype.slice.call(arguments))); 
    }; 
  };
}

Przykład

bind () - Dokumentacja PrototypeJS

Andy E.
źródło
Z braku zainteresowania, jaka jest różnica między Array.prototype.slice.call(arguments)i arguments.slice()?
sje397,
7
@ sje397: argumenty nie są * prawdziwą * tablicą, więc nie ma metody slice () . Jednak metoda slice () na Array.prototype jest celowo ogólna, więc można przekazać dowolny obiekt, który ma indeksy liczbowe i właściwość length, i zadziała.
Andy E
2
To najbardziej elegancka odpowiedź
antoine
To .bind () jest naprawdę świetne i znacznie rozszerza użycie i prostotę wywołań zwrotnych. Jako podstawową próbkę do zrozumienia, jeśli masz:f = function(arg1,arg2){alert(arg1+arg2);}.bind(this,"abc"); f("def") // Gives "abcdef"
Le Droid
To naprawdę grt odpowiedź. Świetnie i działa dobrze dla mnie. Dziękuję :)
Wisznu Miszra,
13

Jeśli masz wywołanie zwrotne, które zostanie wywołane przez coś innego niż kod z określoną liczbą parametrów i chcesz przekazać dodatkowe parametry, możesz przekazać funkcję otoki jako wywołanie zwrotne, a wewnątrz otoki przekazać dodatkowe parametry.

function login(accessedViaPopup) {
    //pass FB.login a call back function wrapper that will accept the
    //response param and then call my "real" callback with the additional param
    FB.login(function(response){
        fb_login_callback(response,accessedViaPopup);
    });
}

//handles respone from fb login call
function fb_login_callback(response, accessedViaPopup) {
    //do stuff
}
Blake Mills
źródło
9

Jeśli nie masz pewności, ile parametrów chcesz przekazać do funkcji zwrotnych, użyj applyfunkcji.

function tryMe (param1, param2) {
  alert (param1 + " and " + param2);
}

function callbackTester(callback,params){
    callback.apply(this,params);
}

callbackTester(tryMe,['hello','goodbye']);
Zeeman Chen
źródło
4

Zawiń przekazane funkcje „potomne” jako argumenty w opakowaniach funkcji, aby zapobiec ich ocenie, gdy zostanie wywołana funkcja „nadrzędna”.

function outcome(){
    return false;
}

function process(callbackSuccess, callbackFailure){
    if ( outcome() )
        callbackSuccess();
    else
        callbackFailure();
}

process(function(){alert("OKAY");},function(){alert("OOPS");})
Alan McCune
źródło
4

Kod z pytania z dowolną liczbą parametrów i kontekstem wywołania zwrotnego:

function SomeFunction(name) {
    this.name = name;
}
function tryMe(param1, param2) {
    console.log(this.name + ":  " + param1 + " and " + param2);
}
function tryMeMore(param1, param2, param3) {
    console.log(this.name + ": " + param1 + " and " + param2 + " and even " + param3);
}
function callbackTester(callback, callbackContext) {
    callback.apply(callbackContext, Array.prototype.splice.call(arguments, 2));
}
callbackTester(tryMe, new SomeFunction("context1"), "hello", "goodbye");
callbackTester(tryMeMore, new SomeFunction("context2"), "hello", "goodbye", "hasta la vista");

// context1: hello and goodbye
// context2: hello and goodbye and even hasta la vista
Adam Skobodzinski
źródło
2

Użyj funkcji curry jak w tym prostym przykładzie.

const BTN = document.querySelector('button')
const RES = document.querySelector('p')

const changeText = newText => () => {
  RES.textContent = newText
}

BTN.addEventListener('click', changeText('Clicked!'))
<button>ClickMe</button>
<p>Not clicked<p>


źródło
0

Nowa wersja dla scenariusza, w którym wywołanie zwrotne zostanie wywołane przez inną funkcję, a nie przez własny kod, i chcesz dodać dodatkowe parametry.

Na przykład, udawajmy, że masz wiele zagnieżdżonych wywołań z wywołaniami zwrotnymi powodzenia i błędów. W tym przykładzie użyję obietnic kątowych, ale każdy kod javascript z wywołaniami zwrotnymi byłby taki sam w tym celu.

someObject.doSomething(param1, function(result1) {
  console.log("Got result from doSomething: " + result1);
  result.doSomethingElse(param2, function(result2) {
    console.log("Got result from doSomethingElse: " + result2);
  }, function(error2) {
    console.log("Got error from doSomethingElse: " + error2);
  });
}, function(error1) {
  console.log("Got error from doSomething: " + error1);
});

Teraz możesz chcieć uporządkować kod, definiując funkcję rejestrowania błędów, zachowując źródło błędu do celów debugowania. W ten sposób przebudujesz kod:

someObject.doSomething(param1, function (result1) {
  console.log("Got result from doSomething: " + result1);
  result.doSomethingElse(param2, function (result2) {
    console.log("Got result from doSomethingElse: " + result2);
  }, handleError.bind(null, "doSomethingElse"));
}, handleError.bind(null, "doSomething"));

/*
 * Log errors, capturing the error of a callback and prepending an id
 */
var handleError = function (id, error) {
  var id = id || "";
  console.log("Got error from " + id + ": " + error);
};

Funkcja wywołująca nadal doda parametr błędu po parametrach funkcji wywołania zwrotnego.

Juangui Jordán
źródło
0

Szukałem tego samego i znalazłem rozwiązanie, a oto prosty przykład, jeśli ktoś chce przez to przejść.

var FA = function(data){
   console.log("IN A:"+data)
   FC(data,"LastName");
};
var FC = function(data,d2){
   console.log("IN C:"+data,d2)
};
var FB = function(data){
   console.log("IN B:"+data);
    FA(data)
};
FB('FirstName')

Wysłano również na inne pytanie tutaj

Code_Crash
źródło
0

Pozwól, że dam ci bardzo prosty przykład użycia wywołania zwrotnego w stylu Node.js:

/**
 * Function expects these arguments: 
 * 2 numbers and a callback function(err, result)
 */
var myTest = function(arg1, arg2, callback) {
  if (typeof arg1 !== "number") {
    return callback('Arg 1 is not a number!', null); // Args: 1)Error, 2)No result
  }
  if (typeof arg2 !== "number") {
    return callback('Arg 2 is not a number!', null); // Args: 1)Error, 2)No result
  }
  if (arg1 === arg2) {
    // Do somethign complex here..
    callback(null, 'Actions ended, arg1 was equal to arg2'); // Args: 1)No error, 2)Result
  } else if (arg1 > arg2) {
    // Do somethign complex here..
    callback(null, 'Actions ended, arg1 was > from arg2'); // Args: 1)No error, 2)Result
  } else {
    // Do somethign else complex here..
    callback(null, 'Actions ended, arg1 was < from arg2'); // Args: 1)No error, 2)Result
  }
};


/**
 * Call it this way: 
 * Third argument is an anonymous function with 2 args for error and result
 */
myTest(3, 6, function(err, result) {
  var resultElement = document.getElementById("my_result");
  if (err) {
    resultElement.innerHTML = 'Error! ' + err;
    resultElement.style.color = "red";
    //throw err; // if you want
  } else {
    resultElement.innerHTML = 'Result: ' + result;
    resultElement.style.color = "green";
  }
});

oraz HTML, który wyświetli wynik:

<div id="my_result">
  Result will come here!
</div>

Możesz się nim pobawić tutaj: https://jsfiddle.net/q8gnvcts/ - na przykład spróbuj przekazać ciąg zamiast liczby: myTest („jakiś ciąg”, 6, funkcja (err, wynik) .. i zobacz wynik.

Mam nadzieję, że ten przykład pomoże, ponieważ reprezentuje on bardzo podstawowe pojęcie funkcji zwrotnych.

Vlado
źródło
0
function tryMe(param1, param2) {
  console.log(param1 + " and " + param2);
}

function tryMe2(param1) {
  console.log(param1);
}

function callbackTester(callback, ...params) {
  callback(...params);
}



callbackTester(tryMe, "hello", "goodbye");

callbackTester(tryMe2, "hello");

czytaj więcej o składni spreadu

Dmitrij Grinko
źródło
0
//Suppose function not taking any parameter means just add the GetAlterConfirmation(function(result) {});
GetAlterConfirmation('test','messageText',function(result) {
                        alert(result);
    }); //Function into document load or any other click event.


function GetAlterConfirmation(titleText, messageText, _callback){
         bootbox.confirm({
                    title: titleText,
                    message: messageText,
                    buttons: {
                        cancel: {
                            label: '<i class="fa fa-times"></i> Cancel'
                        },
                        confirm: {
                            label: '<i class="fa fa-check"></i> Confirm'
                        }
                    },
                    callback: function (result) {
                        return _callback(result); 
                    }
                });
Santhos Jery
źródło
1
Dodaj wyjaśnienie tego, co robisz i dlaczego :)
Preston Badeer
Okej, zrobię od następnej odpowiedzi, przepraszam za powyższe, ponieważ jest to moja pierwsza odpowiedź.
Santhos Jery,