JavaScript: Melewati parameter ke fungsi panggilan balik

289

Saya mencoba meneruskan beberapa parameter ke fungsi yang digunakan sebagai panggilan balik, bagaimana saya bisa melakukannya?

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

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

callbackTester (tryMe, "hello", "goodbye");
vitto
sumber
9
Apa yang Anda lakukan harus berhasil. Masalah apa yang Anda miliki
Daniel Vassallo
1
Kode Anda berfungsi dengan baik, apa masalahnya?
Sarfraz
1
Ini seharusnya bekerja ... jsfiddle.net/QXQZj
Hristo
maaf itu salah saya pada sintaks kode utama, saya pikir ini karena ini adalah pertama kalinya saya menggunakan panggilan balik dalam JavaScript
vitto
Jika Anda ingin menambahkan parameter ke panggilan balik tetapi tidak dapat mengubah apa yang memanggilnya (karena Anda tidak memiliki kekuatan untuk mengubah urutan argumen, Anda dapat pra-mengikat beberapa parameter panggilan balik dengan JS mengikat, seperti yang saya tunjukkan pada jawaban ini: stackoverflow.com/a/28120741/1695680
ThorSummoner

Jawaban:

253

Jika Anda menginginkan sesuatu yang sedikit lebih umum, Anda dapat menggunakan variabel argumen seperti:

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

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

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

Tetapi sebaliknya, contoh Anda berfungsi dengan baik (argumen [0] dapat digunakan sebagai pengganti panggilan balik dalam tester)

Simon Scarfe
sumber
53
Selama kita berada dalam semangat menjadi umum, callback.apply(arguments)sebagai fungsi tubuh untuk callbackTesterdiperluas melampaui dua skenario argumen.
Steven
1
maaf, itu adalah kesalahan sintaksis dalam kode utama, saya pikir ini karena ini adalah pertama kalinya saya menggunakan panggilan balik dalam JavaScript, Anda telah membantu saya untuk memahami itu bukan masalah, dan untuk melihat contoh yang bagus.
vitto
3
FYI, menggunakan fungsi anonim (jawaban Marimuthu) atau .bind () (jawaban Andy) adalah cara yang jauh lebih bersih untuk meneruskan argumen ke panggilan balik.
antoine
203

Ini juga akan berfungsi:

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

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

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

Skenario lain:

// 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
sumber
2
Ini berfungsi dengan baik karena ia juga memungkinkan fungsi anonim untuk mengirimkan parameter seperti: callbackTester (fungsi (data) {tryMe (data, "hello", "selamat tinggal");});
Michael Khalili
Saya juga suka memeriksa bahwa callback sebenarnya adalah sebuah fungsi. if (typeof window[callback] == 'function') window[callback].call(this);
GreeKatrina
63

Pertanyaan Anda tidak jelas. Jika Anda bertanya bagaimana Anda bisa melakukan ini dengan cara yang lebih sederhana, Anda harus melihat pada metode ECMAScript 5th edition .bind () , yang merupakan anggota Function.prototype . Dengan menggunakannya, Anda dapat melakukan sesuatu seperti ini:

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

function callbackTester (callback) {
    callback();
}

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

Anda juga dapat menggunakan kode berikut ini, yang menambahkan metode jika tidak tersedia di browser saat ini:

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

Contoh

bind () - Dokumentasi PrototypeJS

Andy E
sumber
Karena ketertarikan, apa perbedaan antara Array.prototype.slice.call(arguments)dan arguments.slice()?
sje397
7
@ sje397: argumen bukanlah array * nyata *, jadi argumen ini tidak memiliki metode slice () . Namun, metode slice () pada Array.prototype sengaja dibuat generik, sehingga Anda bisa melewatkan objek apa pun yang memiliki indeks numerik dan properti panjang dan itu akan berfungsi.
Andy E
2
Ini adalah jawaban yang paling elegan
antoine
Bind () ini benar-benar hebat dan memperpanjang banyak penggunaan & kesederhanaan panggilan balik. Sebagai sampel dasar untuk memahaminya, jika Anda memiliki:f = function(arg1,arg2){alert(arg1+arg2);}.bind(this,"abc"); f("def") // Gives "abcdef"
Le Droid
Ini benar-benar jawaban grt. Luar biasa dan bekerja dengan baik untuk saya. Terima kasih :)
Wisnu Mishra
13

Ketika Anda memiliki panggilan balik yang akan dipanggil oleh sesuatu selain kode Anda dengan jumlah params tertentu dan Anda ingin meneruskan params tambahan, Anda dapat melewati fungsi wrapper sebagai callback dan di dalam wrapper melewati param tambahan.

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
sumber
9

Jika Anda tidak yakin berapa banyak parameter yang akan dilewatkan ke fungsi panggilan balik, gunakan applyfungsi.

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

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

callbackTester(tryMe,['hello','goodbye']);
Zeeman Chen
sumber
4

Bungkus fungsi 'anak' yang diteruskan sebagai / dengan argumen dalam pembungkus fungsi untuk mencegah mereka dievaluasi ketika fungsi 'orang tua' dipanggil.

function outcome(){
    return false;
}

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

process(function(){alert("OKAY");},function(){alert("OOPS");})
Alan McCune
sumber
4

Kode dari pertanyaan dengan sejumlah parameter dan konteks panggilan balik:

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
sumber
2

Gunakan fungsi kari seperti dalam contoh sederhana ini.

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>


sumber
0

Versi baru untuk skenario di mana panggilan balik akan dipanggil oleh beberapa fungsi lain, bukan kode Anda sendiri, dan Anda ingin menambahkan parameter tambahan.

Misalnya, mari kita berpura-pura memiliki banyak panggilan bersarang dengan panggilan balik sukses dan kesalahan. Saya akan menggunakan janji sudut untuk contoh ini tetapi kode javascript dengan panggilan balik akan sama untuk tujuan tersebut.

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

Sekarang Anda mungkin ingin mengacaukan kode Anda dengan mendefinisikan fungsi untuk mencatat kesalahan, menjaga asal kesalahan untuk tujuan debugging. Ini adalah bagaimana Anda akan melanjutkan untuk memperbaiki kode Anda:

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

Fungsi panggilan masih akan menambahkan parameter kesalahan setelah parameter fungsi panggilan balik Anda.

Juangui Jordán
sumber
0

Saya sedang mencari hal yang sama dan berakhir dengan solusi dan di sini ini adalah contoh sederhana jika ada yang mau melalui ini.

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

Juga diposting pertanyaan lain di sini

Code_Crash
sumber
0

Biarkan saya memberi Anda contoh gaya Node.js yang sangat sederhana menggunakan callback:

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

dan HTML yang akan memberikan hasil:

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

Anda dapat bermain dengannya di sini: https://jsfiddle.net/q8gnvcts/ - misalnya mencoba meneruskan string alih-alih nomor: myTest ('some string', 6, function (err, result) .. dan lihat hasilnya.

Saya harap contoh ini membantu karena ini mewakili ide yang sangat mendasar dari fungsi panggilan balik.

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

baca lebih lanjut tentang sintaks spread

Dmitry Grinko
sumber
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
sumber
1
Silakan tambahkan penjelasan tentang apa yang Anda lakukan dan mengapa :)
Preston Badeer
Oke, saya akan lakukan dari jawaban saya berikutnya, maaf untuk yang di atas karena ini adalah jawaban pertama saya.
Santhos Jery