JavaScript: การส่งพารามิเตอร์ไปยังฟังก์ชันเรียกกลับ


289

ฉันกำลังพยายามส่งพารามิเตอร์บางอย่างไปยังฟังก์ชันที่ใช้เป็นการโทรกลับฉันจะทำเช่นนั้นได้อย่างไร

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

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

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

9
สิ่งที่คุณกำลังทำควรจะทำงาน คุณมีปัญหาอะไร
Daniel Vassallo

1
รหัสของคุณใช้งานได้ดีปัญหาคืออะไร
Sarfraz

1
มันควรจะทำงาน ... jsfiddle.net/QXQZj
Hristo

ขออภัยมันเป็นความผิดของฉันในไวยากรณ์รหัสหลักฉันคิดว่าเป็นเพราะนี่เป็นครั้งแรกที่ฉันใช้การโทรกลับใน JavaScript
vitto

หากคุณต้องการเพิ่มพารามิเตอร์ในการโทรกลับ แต่ไม่สามารถเปลี่ยนสิ่งที่เรียกมันได้ (เนื่องจากคุณไม่มีอำนาจในการเปลี่ยนลำดับการโต้แย้งคุณสามารถผูกพารามิเตอร์การเรียกกลับบางส่วนไว้กับ JS bind ได้ดังที่ฉันได้แสดงไว้บน คำตอบนี้: 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 คุณได้ช่วยให้ฉันเข้าใจว่าไม่ใช่ probelm และเพื่อดูตัวอย่างที่ดี
vitto

3
FYI โดยใช้ฟังก์ชั่นที่ไม่ระบุชื่อ (คำตอบของ Marimuthu) หรือ. ผูก () (คำตอบของ Andy) เป็นวิธีที่สะอาดกว่ามากในการส่งอาร์กิวเมนต์ไปยังการโทรกลับ
ทอน

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 (function (data) {tryMe (data, "hello", "goodbye");});
Michael Khalili

ฉันยังต้องการตรวจสอบว่าการเรียกกลับเป็นจริงฟังก์ชั่น 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 () - เอกสารต้นแบบ PrototypeJS


จากความสนใจความแตกต่างระหว่างArray.prototype.slice.call(arguments)และarguments.slice()คืออะไร
sje397

7
@ sje397: อาร์กิวเมนต์ไม่ใช่อาร์เรย์ * real * ดังนั้นจึงไม่มีเมธอดslice () อย่างไรก็ตามslice ()วิธีการในArray.prototypeนั้นเป็นแบบจงใจดังนั้นคุณสามารถส่งผ่านวัตถุใด ๆ ที่มีดัชนีตัวเลขและคุณสมบัติความยาวและมันจะทำงาน
Andy E

2
นี่คือคำตอบที่หรูหราที่สุด
ทอน

. ผูก () นี้ยอดเยี่ยมมากและใช้งานได้ง่ายมาก เป็นตัวอย่างพื้นฐานที่จะเข้าใจถ้าคุณมี:f = function(arg1,arg2){alert(arg1+arg2);}.bind(this,"abc"); f("def") // Gives "abcdef"
เลอดรอย

นี่เป็นคำตอบที่แท้จริง ยอดเยี่ยมและทำงานได้ดีสำหรับฉัน ขอบคุณ :)
Vishnu Mishra

13

เมื่อคุณมีการเรียกกลับที่จะถูกเรียกโดยสิ่งอื่นนอกเหนือจากรหัสของคุณด้วยจำนวน params ที่เฉพาะเจาะจงและคุณต้องการที่จะผ่านใน params เพิ่มเติมคุณสามารถผ่านฟังก์ชั่น wrapper เป็นโทรกลับและภายใน wrapper ผ่าน param เพิ่มเติม

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

ล้อมฟังก์ชั่น 'child' ที่ถูกส่งผ่านเป็น / โดยมีอาร์กิวเมนต์อยู่ภายในตัวห่อหุ้มฟังก์ชันเพื่อป้องกันไม่ให้ถูกประเมินเมื่อเรียกฟังก์ชัน 'parent'

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

เวอร์ชันใหม่สำหรับสถานการณ์ที่ฟังก์ชันการโทรกลับถูกเรียกใช้โดยบางฟังก์ชันไม่ใช่รหัสของคุณและคุณต้องการเพิ่มพารามิเตอร์เพิ่มเติม

ตัวอย่างเช่นสมมติว่าคุณมีการโทรซ้อนหลายครั้งพร้อมการโทรกลับสำเร็จและข้อผิดพลาด ฉันจะใช้สัญญาเชิงมุมสำหรับตัวอย่างนี้ แต่รหัสจาวาสคริปต์ใด ๆ ที่มีการเรียกกลับจะเหมือนกันสำหรับวัตถุประสงค์

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

ตอนนี้คุณอาจต้องการกระจายรหัสของคุณโดยการกำหนดฟังก์ชั่นเพื่อบันทึกข้อผิดพลาดทำให้ต้นกำเนิดของข้อผิดพลาดสำหรับการแก้ไขจุดบกพร่อง นี่คือวิธีที่คุณจะดำเนินการ refactor รหัสของคุณ:

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
โปรดเพิ่มคำอธิบายเกี่ยวกับสิ่งที่คุณกำลังทำอยู่และทำไม :)
Preston Badeer

โอเคฉันจะทำจากคำตอบถัดไปของฉันขอโทษสำหรับข้างต้นเพราะนี่คือคำตอบแรกของฉัน
Santhos Jery
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.