JavaScript: передача параметрів функції зворотного дзвінка


289

Я намагаюся передати якийсь параметр функції, яка використовується як зворотний виклик, як це зробити?

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

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

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

9
Те, що ви робите, має працювати. Які проблеми у вас є?
Даніель Вассалло

1
Ваш код працює добре, в чому проблема?
Сарфраз

1
Це повинно працювати ... jsfiddle.net/QXQZj
Hristo,

Вибачте, що я винен у синтаксисі основного коду, я подумав, що це тому, що це перший раз, коли я використовую зворотний дзвінок у JavaScript
vitto

Якщо ви хочете додати параметри до зворотного дзвінка, але не можете змінити те, що викликає його (так як у вас немає сили змінювати порядок аргументів, ви можете попередньо зв’язати деякі параметри зворотного виклику за допомогою прив'язки JS, як я показав на ця відповідь: stackoverflow.com/a/28120741/1695680
ThorSummoner

Відповіді:


253

Якщо ви хочете щось трохи більш загальне, ви можете використовувати змінну аргументи на зразок так:

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

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

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

Але в іншому випадку ваш приклад працює чудово (аргументи [0] можна використовувати замість зворотного виклику в тестері)


53
Поки ми перебуваємо в дусі бути загальним, callback.apply(arguments)тому що орган функції може бути callbackTesterдоступним за межами двох сценаріїв аргументів.
Стівен

1
Вибачте, це була синтаксична помилка в основному коді, я думав, що це тому, що це перший раз, коли я використовую зворотний виклик у JavaScript, ви допомогли мені зрозуміти, що це не проблема, і побачити чудовий приклад.
vitto

3
FYI, використовуючи анонімну функцію (відповідь Марімутху) або .bind () (відповідь Енді), є набагато більш чіткими способами передачі аргументів до зворотного дзвінка.
антоїн

203

Це також працює:

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

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

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

Інший сценарій:

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

2
Це чудово, оскільки він також дозволяє анонімній функції передавати такі параметри: callbackTester (функція (дані) {tryMe (дані, "привіт", "до побачення");});
Майкл Халілі

Я також хотів би перевірити, що зворотний виклик є насправді функцією. if (typeof window[callback] == 'function') window[callback].call(this);
GreeKatrina

63

Ваше питання незрозуміле. Якщо ви запитуєте, як це зробити більш простим способом, вам слід поглянути на метод ECMAScript 5-го видання .bind () , який є членом Function.prototype . Використовуючи його, ви можете зробити щось подібне:

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

function callbackTester (callback) {
    callback();
}

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

Ви також можете використовувати наступний код, який додає метод, якщо він недоступний у поточному браузері:

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

Приклад

bind () - Документація прототипу JS


З інтересу, в чому різниця між Array.prototype.slice.call(arguments)і arguments.slice()?
sje397

7
@ sje397: аргументи - це не * real * масив, тому у нього немає методу slice () . Однак метод slice () у Array.prototype навмисно є загальним, тому ви можете передавати будь-який об’єкт, що має числові індекси та властивість довжини, і він буде працювати.
Енді Е

2
Це найелегантніша відповідь
антоїн

Цей .bind () дійсно чудовий і значно розширює використання та простоту зворотних викликів. Як основний зразок, щоб зрозуміти це, якщо у вас є:f = function(arg1,arg2){alert(arg1+arg2);}.bind(this,"abc"); f("def") // Gives "abcdef"
Le Droid,

Це дійсно grt відповідь. Дивовижно і добре працює для мене. Дякую :)
Vishnu Mishra

13

Коли у вас є зворотний дзвінок, який буде викликаний чимось іншим, ніж ваш код із певною кількістю парам, і ви хочете передати додаткові параметри, ви можете передавати функцію обгортки як зворотний виклик, а всередині обгортки передайте додаткові параметри.

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
}

9

Якщо ви не впевнені, скільки параметрів буде передано у функції зворотного дзвінка, скористайтеся applyфункцією.

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

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

callbackTester(tryMe,['hello','goodbye']);

4

Оберніть «дочірні» функції (и), передані як / з аргументами в обгортки функцій, щоб запобігти їх оцінці під час виклику функції «батьків».

function outcome(){
    return false;
}

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

process(function(){alert("OKAY");},function(){alert("OOPS");})

4

Код із запитання з будь-якою кількістю параметрів та контекстом зворотного виклику:

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

2

Використовуйте функцію curried, як у цьому простому прикладі.

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>


0

Нова версія для сценарію, коли зворотний виклик буде викликаний якоюсь іншою функцією, а не власним кодом, і ви хочете додати додаткові параметри.

Наприклад, зробимо вигляд, що у вас багато вкладених дзвінків з успіхом та помилками викликів. Я буду використовувати кутові обіцянки для цього прикладу, але будь-який код JavaScript з зворотними викликами буде однаковим для цієї мети.

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

Тепер ви, можливо, захочете скасувати ваш код, визначивши функцію журналу помилок, зберігаючи походження помилки для цілей налагодження. Ось як би ви перейшли до рефакторного коду:

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

Функція виклику все одно додасть параметр помилки після параметрів функції зворотного виклику.


0

Я шукав те саме і закінчував рішення, і ось простий приклад, якщо хтось хоче пройти це.

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

Також розміщено на іншому питанні тут


0

Дозвольте навести вам дуже простий приклад стилю 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";
  }
});

і HTML, який надасть результат:

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

Ви можете грати з ним тут: https://jsfiddle.net/q8gnvcts/ - наприклад, спробуйте передати рядок замість числа: myTest ('деяка рядок', 6, функція (помилка, результат) .. і побачити результат.

Я сподіваюся, що цей приклад допомагає, оскільки він представляє саму основну ідею функцій зворотного виклику.


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

читати докладніше про синтаксис розповсюдження


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

1
Будь ласка, додайте пояснення, що ви робите та чому :)
Престон Бідєр

Гаразд, я зроблю свою наступну відповідь, вибачте за сказане, бо це моя перша відповідь.
Santhos Jery
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.