JavaScript: Truyền tham số cho hàm gọi lại


289

Tôi đang cố gắng truyền một số tham số cho một hàm được sử dụng như gọi lại, làm thế nào tôi có thể làm điều đó?

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

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

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

9
Những gì bạn đang làm nên làm việc. Bạn có vấn đề gì?
Daniel Vassallo

1
Mã của bạn hoạt động tốt, vấn đề là gì?
Sarfraz

1
Nó sẽ hoạt động ... jsfiddle.net/QXQZj
Hristo

xin lỗi, đó là lỗi của tôi về cú pháp mã chính, tôi nghĩ đó là vì đây là lần đầu tiên tôi sử dụng một cuộc gọi lại trong JavaScript
vitto

Nếu bạn muốn thêm tham số vào một cuộc gọi lại nhưng không thể thay đổi cách gọi nó (vì bạn không có quyền thay đổi thứ tự đối số, bạn có thể liên kết trước một số tham số gọi lại bằng liên kết JS, như tôi đã trình bày trên câu trả lời này: stackoverflow.com/a/28120741/1695680
ThorSummoner

Câu trả lời:


253

Nếu bạn muốn một cái gì đó tổng quát hơn một chút, bạn có thể sử dụng biến đối số như vậy:

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

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

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

Nhưng nếu không, ví dụ của bạn hoạt động tốt (đối số [0] có thể được sử dụng thay cho cuộc gọi lại trong trình kiểm tra)


53
Chừng nào chúng ta còn có tinh thần chung chung, callback.apply(arguments)vì cơ thể chức năng cho callbackTestercó thể mở rộng ra ngoài kịch bản hai đối số.
Steven

1
xin lỗi, đó là lỗi cú pháp trong mã chính, tôi nghĩ là vì đây là lần đầu tiên tôi sử dụng hàm gọi lại trong JavaScript, bạn đã giúp tôi hiểu đó không phải là bản thử nghiệm và để xem một ví dụ tuyệt vời.
vitto

3
FYI, sử dụng một hàm ẩn danh (câu trả lời của Marimuthu) hoặc .bind () (câu trả lời của Andy) là những cách sạch sẽ hơn nhiều để chuyển các đối số cho một cuộc gọi lại.
antoine

203

Điều này cũng sẽ làm việc:

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

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

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

Một kịch bản khác:

// 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
Điều này hoạt động rất tốt vì nó cũng cho phép hàm ẩn danh truyền các tham số như vậy: callbackTester (function (data) {tryMe (data, "hello", "goodbye");});
Michael Khalili

Tôi cũng muốn kiểm tra xem thực tế gọi lại là một chức năng. if (typeof window[callback] == 'function') window[callback].call(this);
GreeKatrina

63

Câu hỏi của bạn không rõ ràng. Nếu bạn đang hỏi làm thế nào bạn có thể làm điều này theo cách đơn giản hơn, bạn nên xem phương thức ấn bản thứ 5 của ECMAScript .bind () , một thành viên của Function.prototype . Sử dụng nó, bạn có thể làm một cái gì đó như thế này:

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

function callbackTester (callback) {
    callback();
}

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

Bạn cũng có thể sử dụng mã sau, thêm phương thức nếu nó không khả dụng trong trình duyệt hiện tại:

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

Thí dụ

bind () - Tài liệu PrototypeJS


Không quan tâm, sự khác biệt giữa Array.prototype.slice.call(arguments)arguments.slice()?
sje394

7
@ sje394: đối số không phải là mảng * thực *, vì vậy nó không có phương thức lát () . Tuy nhiên, phương thức lát () trên Array.prototype có chủ ý chung chung, vì vậy bạn có thể vượt qua bất kỳ đối tượng nào có chỉ số bằng số và thuộc tính độ dài và nó sẽ hoạt động.
Andy E

2
Đây là câu trả lời tao nhã nhất
antoine

.Bind () này thực sự tuyệt vời và mở rộng rất nhiều việc sử dụng & đơn giản của các cuộc gọi lại. Là một mẫu cơ bản để hiểu nó, nếu bạn có:f = function(arg1,arg2){alert(arg1+arg2);}.bind(this,"abc"); f("def") // Gives "abcdef"
Le Droid

Đây thực sự là một câu trả lời grt. Tuyệt vời và làm việc tốt cho tôi. Cảm ơn bạn :)
Vishnu Mishra

13

Khi bạn có một cuộc gọi lại sẽ được gọi bởi một thứ khác ngoài mã của bạn với một số tham số cụ thể và bạn muốn chuyển vào các tham số bổ sung, bạn có thể chuyển một hàm bao bọc khi gọi lại và bên trong trình bao bọc vượt qua các tham số bổ sung.

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

Nếu bạn không chắc chắn có bao nhiêu tham số bạn sẽ được chuyển vào các hàm gọi lại, hãy sử dụng applyhàm.

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

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

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

4

Bao (các) hàm 'con' được truyền dưới dạng / với các đối số trong các hàm bao hàm để ngăn chúng được đánh giá khi hàm 'cha' được gọi.

function outcome(){
    return false;
}

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

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

4

Mã từ một câu hỏi với bất kỳ số lượng tham số và bối cảnh gọi lại:

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

Sử dụng hàm curried như trong ví dụ đơn giản này.

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

Một phiên bản mới cho kịch bản trong đó gọi lại sẽ được gọi bởi một số chức năng khác, không phải mã của riêng bạn và bạn muốn thêm các tham số bổ sung.

Ví dụ: giả sử bạn có rất nhiều cuộc gọi lồng nhau với các cuộc gọi lại thành công và lỗi. Tôi sẽ sử dụng các lời hứa góc cạnh cho ví dụ này nhưng bất kỳ mã javascript nào có hàm gọi lại đều giống nhau cho mục đích này.

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

Bây giờ bạn có thể muốn giải nén mã của mình bằng cách xác định hàm để ghi lỗi, giữ nguyên nguồn gốc của lỗi cho mục đích gỡ lỗi. Đây là cách bạn sẽ tiến hành cấu trúc lại mã của mình:

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

Hàm gọi sẽ vẫn thêm tham số lỗi sau các tham số chức năng gọi lại của bạn.


0

Tôi đã tìm kiếm điều tương tự và kết thúc với giải pháp và đây là một ví dụ đơn giản nếu có ai muốn trải qua điều này.

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

Cũng được đăng trên các câu hỏi khác ở đây


0

Để tôi cung cấp cho bạn một ví dụ kiểu Node.js rất đơn giản về cách sử dụng hàm gọi lại:

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

và HTML sẽ hiển thị kết quả:

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

Bạn có thể chơi với nó tại đây: https://jsfiddle.net/q8gnvcts/ - ví dụ: thử truyền chuỗi thay vì số: myTest ('một số chuỗi', 6, hàm (err, result) .. và xem kết quả.

Tôi hy vọng ví dụ này có ích vì nó thể hiện ý tưởng rất cơ bản về các hàm gọi lại.


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

đọc thêm về cú pháp lây lan


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
Vui lòng thêm một lời giải thích về những gì bạn đang làm và tại sao :)
Preston Badeer

Được rồi, tôi sẽ làm từ câu trả lời tiếp theo của tôi, xin lỗi vì ở trên vì đây là câu trả lời đầu tiên của tôi.
Santhos Jery
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.