Truyền một hàm JavaScript làm tham số


665

Làm cách nào để tôi truyền một hàm làm tham số mà không thực hiện chức năng trong hàm "cha" hoặc sử dụng eval()? (Vì tôi đã đọc rằng nó không an toàn.)

Tôi có cái này:

addContact(entityId, refreshContactList());

Nó hoạt động, nhưng vấn đề là refreshContactListkích hoạt khi hàm được gọi, thay vì khi nó được sử dụng trong hàm.

Tôi có thể sử dụng nó eval(), nhưng đó không phải là cách tốt nhất, theo những gì tôi đã đọc. Làm cách nào tôi có thể truyền một hàm làm tham số trong JavaScript?

Câu trả lời:


929

Bạn chỉ cần xóa dấu ngoặc đơn:

addContact(entityId, refreshContactList);

Điều này sau đó vượt qua chức năng mà không thực hiện nó đầu tiên.

Đây là một ví dụ:

function addContact(id, refreshCallback) {
    refreshCallback();
    // You can also pass arguments if you need to
    // refreshCallback(id);
}

function refreshContactList() {
    alert('Hello World');
}

addContact(1, refreshContactList);

6
@stevefenton, hãy xem xét cập nhật câu trả lời của bạn với bình luận h2ooooooo, nó sẽ rất hữu ích.
Morgan Wilde

5
Dựa trên câu hỏi, cuộc gọi lại không chấp nhận các tham số, đó là lý do tại sao tôi bỏ chúng ra khỏi ví dụ. Tôi sẽ thêm một nhận xét về nó.
Fenton

4
@Veverke Nó sẽ trông như thế này ...addContact(1, function(id) { console.log(id); });
Fenton

4
@Steve Fenton: sau khi đọc câu trả lời của bạn, tôi đã tự hỏi tại sao tôi lại hỏi ... :-)
Veverke

1
Cú pháp lớp trong ECMAScript sẽ không có =dấu ... class myFuncs {hơn là class myFuncs = {. Bạn cũng cần phải chạy trong một môi trường hỗ trợ cú pháp lớp (chưa phải tất cả các trình duyệt đều hỗ trợ nó). Nếu bạn vẫn đang vật lộn, nó có thể phù hợp hơn với một câu hỏi hoàn toàn mới vì vấn đề của bạn không phải là về việc truyền các hàm - đó là cú pháp ES chung.
Fenton

336

Nếu bạn muốn truyền một hàm, chỉ cần tham chiếu nó theo tên mà không có dấu ngoặc đơn:

function foo(x) {
    alert(x);
}
function bar(func) {
    func("Hello World!");
}

//alerts "Hello World!"
bar(foo);

Nhưng đôi khi bạn có thể muốn vượt qua một chức năng có các đối số được bao gồm , nhưng không được gọi cho đến khi gọi lại được gọi. Để làm điều này, khi gọi nó, chỉ cần bọc nó trong một hàm ẩn danh, như thế này:

function foo(x) {
   alert(x);
}
function bar(func) {
   func();
}

//alerts "Hello World!" (from within bar AFTER being passed)
bar(function(){ foo("Hello World!") });

Nếu bạn thích, bạn cũng có thể sử dụng hàm áp dụng và có một tham số thứ ba là một mảng các đối số, như:

function eat(food1, food2)
{
    alert("I like to eat " + food1 + " and " + food2 );
}
function myFunc(callback, args)
{
    //do stuff
    //...
    //execute callback when finished
    callback.apply(this, args);
}

//alerts "I like to eat pickles and peanut butter"
myFunc(eat, ["pickles", "peanut butter"]); 

70
điều này nên được xếp hạng cao hơn vì anh ta cũng giải quyết làm thế nào để vượt qua một hàm với các đối số
deltanine

3
Và một điều tôi sẽ thêm vào đó là tính năng này một mình - có thể truyền các hàm JavaScript dưới dạng đối số hoặc biến hoặc tương tự - là tính năng giúp JavaScript trở nên mạnh mẽ và tuyệt vời để mã hóa.
TheHansinator 9/12/2015

@ Compynerd255 Tôi đồng ý, điều này và khả năng nhanh chóng tạo ra các đối tượng theo nghĩa đen là hai khía cạnh yêu thích của tôi về Javascript. Tôi luôn bỏ lỡ các đối tượng bằng chữ trong các ngôn ngữ không có chúng.
dallin

3
Tôi rất biết ơn Javascript đã cung cấp tính năng này và cho bạn @dallin để cho tôi biết rằng nó tồn tại.
Dipendu Paul

Đối với ví dụ "bọc nó trong một hàm ẩn danh", trong trường hợp không rõ ràng, hàm ẩn danh sẽ trả về chính hàm đó (với các tham số) và nó được gọi khi nó đạt đến dấu ngoặc đơn trong func (). Điều này khiến tôi mất một thời gian để tìm ra, vì vậy tôi nghĩ rằng nó có thể giúp đỡ người khác.
hubpixel

51

Ví dụ 1:

funct("z", function (x) { return x; });

function funct(a, foo){
    foo(a) // this will return a
}

Ví dụ 2:

function foodemo(value){
    return 'hello '+value;
}

function funct(a, foo){
    alert(foo(a));
}

//call funct    
funct('world!',foodemo); //=> 'hello world!'

nhìn này


ở ví dụ đầu tiên, bạn nên thêm từ khóa return, như thế này: function func (a, foo) {return foo (a) // cái này sẽ trả về a} nếu không bạn sẽ không xác định được
Artem Fedotov

34

Để truyền hàm dưới dạng tham số, chỉ cần xóa dấu ngoặc!

function ToBeCalled(){
  alert("I was called");
}

function iNeedParameter( paramFunc) {
   //it is a good idea to check if the parameter is actually not null
   //and that it is a function
   if (paramFunc && (typeof paramFunc == "function")) {
      paramFunc();   
   }
}

//this calls iNeedParameter and sends the other function to it
iNeedParameter(ToBeCalled); 

Ý tưởng đằng sau điều này là một hàm khá giống với một biến. Thay vì viết

function ToBeCalled() { /* something */ }

bạn cũng có thể viết

var ToBeCalledVariable = function () { /* something */ }

Có hai sự khác biệt nhỏ giữa hai cái, nhưng dù sao đi nữa - cả hai đều là những cách hợp lệ để xác định hàm. Bây giờ, nếu bạn xác định một hàm và gán nó một cách rõ ràng cho một biến, thì có vẻ khá logic, rằng bạn có thể chuyển nó làm tham số cho hàm khác và bạn không cần dấu ngoặc:

anotherFunction(ToBeCalledVariable);

2
Chỉ cần typeof paramFunc == "function"là đủ, vì nếu nó không thể gọi được, thì bạn có thể bỏ qua nó.
Jimmy Knoot 10/03/2015

16

Có một cụm từ trong số các lập trình viên JavaScript: "Eval is Evil" vì vậy hãy cố gắng tránh nó bằng mọi giá!

Ngoài câu trả lời của Steve Fenton, bạn cũng có thể truyền trực tiếp các chức năng.

function addContact(entity, refreshFn) {
    refreshFn();
}

function callAddContact() {
    addContact("entity", function() { DoThis(); });
}

8

Tôi đã cắt hết tóc với vấn đề đó. Tôi không thể làm cho các ví dụ trên hoạt động, vì vậy tôi đã kết thúc như sau:

function foo(blabla){
    var func = new Function(blabla);
    func();
}
// to call it, I just pass the js function I wanted as a string in the new one...
foo("alert('test')");

Và nó hoạt động như một bùa mê ... cho những gì tôi cần ít nhất. Hy vọng nó có thể giúp một số.


6

Tôi đề nghị đặt các tham số trong một mảng, và sau đó phân tách chúng bằng cách sử dụng .apply()hàm. Vì vậy, bây giờ chúng ta có thể dễ dàng vượt qua một hàm với nhiều tham số và thực hiện nó một cách đơn giản.

function addContact(parameters, refreshCallback) {
    refreshCallback.apply(this, parameters);
}

function refreshContactList(int, int, string) {
    alert(int + int);
    console.log(string);
}

addContact([1,2,"str"], refreshContactList); //parameters should be putted in an array

5

Bạn cũng có thể sử dụng eval()để làm điều tương tự.

//A function to call
function needToBeCalled(p1, p2)
{
    alert(p1+"="+p2);
}

//A function where needToBeCalled passed as an argument with necessary params
//Here params is comma separated string
function callAnotherFunction(aFunction, params)
{
    eval(aFunction + "("+params+")");
}

//A function Call
callAnotherFunction("needToBeCalled", "10,20");

Đó là nó. Tôi cũng đang tìm kiếm giải pháp này và đã thử các giải pháp được cung cấp trong các câu trả lời khác nhưng cuối cùng nó đã hoạt động từ ví dụ trên.


2

Đây là một cách tiếp cận khác:

function a(first,second)    
{        
return (second)(first);           
}     

a('Hello',function(e){alert(e+ ' world!');}); //=> Hello world     

2

Trong thực tế, có vẻ như một chút phức tạp, là không.

lấy phương thức làm tham số:

 function JS_method(_callBack) { 

           _callBack("called");  

        }

Bạn có thể đưa ra như một phương thức tham số:

    JS_method(function (d) {
           //Finally this will work.
           alert(d)
    });

1
Xin vui lòng, giải thích câu trả lời của bạn.
MillaresRoo

2

Các câu trả lời khác thực hiện một công việc tuyệt vời mô tả những gì đang diễn ra, nhưng một "gotcha" quan trọng là đảm bảo rằng bất cứ điều gì bạn đi qua thực sự là một tham chiếu đến một chức năng.

Chẳng hạn, nếu bạn chuyển qua một chuỗi thay vì một hàm, bạn sẽ gặp lỗi:

function function1(my_function_parameter){
    my_function_parameter();   
}

function function2(){
 alert('Hello world');   
}

function1(function2); //This will work

function1("function2"); //This breaks!

Xem JsFiddle


0

Đôi khi bạn cần phải đối phó với xử lý sự kiện vì vậy cần phải vượt qua sự kiện cũng như một đối số, hầu hết các thư viện hiện đại như phản ứng, góc cạnh có thể cần điều này.

Tôi cần ghi đè chức năng OnSubmit (chức năng từ thư viện bên thứ ba) với một số xác thực tùy chỉnh trên Reacjs và tôi đã truyền chức năng và sự kiện cả hai như bên dưới

NGUỒN GỐC

    <button className="img-submit" type="button"  onClick=
 {onSubmit}>Upload Image</button>

Làm cho một CHỨC NĂNG MỚI uploadvà được gọi thông qua onSubmitvà sự kiện như là đối số

<button className="img-submit" type="button"  onClick={this.upload.bind(this,event,onSubmit)}>Upload Image</button>

upload(event,fn){
  //custom codes are done here
  fn(event);
}

-3

Bạn cũng có thể sử dụng JSON để lưu trữ và gửi các hàm JS.

Kiểm tra lượt theo dõi:

var myJSON = 
{
    "myFunc1" : function (){
        alert("a");
    }, 
    "myFunc2" : function (functionParameter){
        functionParameter();
    }
}



function main(){
    myJSON.myFunc2(myJSON.myFunc1);
}

Điều này sẽ in 'a'.

Những điều sau đây có tác dụng tương tự với những điều trên:

var myFunc1 = function (){
    alert('a');
}

var myFunc2 = function (functionParameter){
    functionParameter();
}

function main(){
    myFunc2(myFunc1);
}

Điều này cũng có tác dụng tương tự với những điều sau đây:

function myFunc1(){
    alert('a');
}


function myFunc2 (functionParameter){
    functionParameter();
}

function main(){
    myFunc2(myFunc1);
}

Và một mô hình đối tượng sử dụng Class làm nguyên mẫu đối tượng:

function Class(){
    this.myFunc1 =  function(msg){
        alert(msg);
    }

    this.myFunc2 = function(callBackParameter){
        callBackParameter('message');
    }
}


function main(){    
    var myClass = new Class();  
    myClass.myFunc2(myClass.myFunc1);
}

9
Ví dụ mã hàng đầu của bạn không phải là JSON. Đây là một đối tượng JavaScript tiêu chuẩn. Bạn cũng không thể gửi / nhận các hàm trong JSON.
Matthew Layton
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.