2009-01-27 8 views
159

Tôi hiểu việc chuyển một hàm sang một hàm khác dưới dạng gọi lại và thực thi hàm đó, nhưng tôi không hiểu cách triển khai tốt nhất để thực hiện điều đó. Tôi đang tìm một ví dụ rất cơ bản, như thế này:Hiểu rõ hơn về các chức năng gọi lại trong JavaScript

var myCallBackExample = { 
    myFirstFunction : function(param1, param2, callback) { 
     // Do something with param1 and param2. 
     if (arguments.length == 3) { 
      // Execute callback function. 
      // What is the "best" way to do this? 
     } 
    }, 
    mySecondFunction : function() { 
     myFirstFunction(false, true, function() { 
      // When this anonymous function is called, execute it. 
     }); 
    } 
}; 

Trong myFirstFunction, nếu tôi làm trở callback mới(), sau đó nó hoạt động và thực hiện các chức năng ẩn danh, nhưng điều đó không có vẻ như đúng tiếp cận với tôi.

+0

Đúng theo nghĩa nào? Thông thường các callback được sử dụng cho các trình xử lý sự kiện - đáng chú ý nhất là các cuộc gọi Ajax, không đồng bộ - về cơ bản những thứ mà bạn không biết khi nào (hoặc nếu) một resposne sẽ đến. – cletus

+2

theo cách các đối số là mảng giống như không phải mảng, vì vậy bạn không thể làm đối số.length nhưng bạn có thể chuyển đổi nó thành một mảng bằng cách sử dụng phương thức slice ... – paul

+1

@paul, mặc dù bạn đúng rằng 'đối số' không phải là một mảng, bạn vẫn có thể tham chiếu chiều dài của nó là 'arguments.length' - hãy thử. Thuộc tính này đề cập đến số đối số thực sự được truyền vào và không nhất thiết là số tham số trong chữ ký hàm. – hotshot309

Trả lời

129

Bạn chỉ có thể nói

callback(); 

Hoặc bạn có thể sử dụng phương pháp call nếu bạn muốn điều chỉnh giá trị this trong khi gọi lại.

callback.call(newValueForThis); 

Bên trong chức năng this sẽ là bất cứ điều gì newValueForThis là.

6

Gọi lại là về tín hiệu và "mới" là về việc tạo các cá thể đối tượng.

Trong trường hợp này thậm chí còn phù hợp hơn để thực thi chỉ "callback();" hơn "trả về cuộc gọi lại mới()" bởi vì bạn không làm bất kỳ điều gì với giá trị trả lại.

(Và các thử nghiệm arguments.length == 3 thực sự là phiền phức, fwiw, tốt hơn để kiểm tra xem callback param tồn tại và là một hàm.)

34

Có 3 khả năng chính để thực hiện một chức năng:

var callback = function(x, y) { 
    // "this" may be different depending how you call the function 
    alert(this); 
}; 
  1. callback (ARGUMENT_1, ARGUMENT_2);
  2. callback.call (some_object, argument_1, argument_2);
  3. callback.apply (some_object, [argument_1, argument_2]);

Các bạn chọn phương pháp phụ thuộc vào việc:

  1. Bạn có các đối số được lưu trữ trong một mảng hoặc các biến như riêng biệt.
  2. Bạn muốn gọi hàm đó trong ngữ cảnh của một số đối tượng. Trong trường hợp này, việc sử dụng từ khóa "this" trong hàm gọi lại đó sẽ tham chiếu đối tượng được truyền làm đối số trong hàm call() hoặc apply(). Nếu bạn không muốn vượt qua ngữ cảnh đối tượng, hãy sử dụng null hoặc undefined. Trong trường hợp sau, đối tượng chung sẽ được sử dụng cho "this".

Documents cho Function.call, Function.apply

6

việc thực hiện đúng sẽ là:

if(callback) callback(); 

điều này làm cho các tham số callback tùy chọn ..

+0

Điều gì xảy ra nếu đối số gọi lại không phải là một hàm? –

88

Bạn nên kiểm tra nếu gọi lại tồn tại, và là một chức năng thực thi:

if (callback && typeof(callback) === "function") { 
    // execute the callback, passing parameters as necessary 
    callback(); 
} 

Rất nhiều thư viện (jQuery, võ đường, vv) sử dụng một mô hình tương tự cho các chức năng không đồng bộ của họ, cũng như nút .js cho tất cả các chức năng không đồng bộ (nodejs thường vượt qua errordata để gọi lại). Nhìn vào mã nguồn của họ sẽ giúp!

+0

Tại sao bạn truyền 'callback' thành chuỗi và sau đó kiểm tra kiểu của nó? Điều này sẽ nâng cao hiệu suất? Điều này giống như kiểm tra kiểu, kiểm tra nếu boolean được chuyển đổi trả về true và sau đó kiểm tra kiểu của nó một lần nữa và thử nghiệm nó với chuỗi ... Bạn có thể giải thích tại sao không? – headacheCoder

+0

Tôi tò mò tại sao bạn cần xác nhận đầu tiên cho gọi lại ... là nó để kiểm tra null hoặc không xác định? Sẽ không 'typeof (gọi lại)' đạt được điều đó cho bạn? 'typeof (null) ===" Đối tượng "', 'typeof (" không xác định ") ===" không xác định "' – PJH

+1

Ngắn mạch VÀ. Nếu cuộc gọi lại không tồn tại, đừng bận tâm đến việc tính toán kiểu của nó. Mặc dù, bạn nói đúng. Nó không phải là cần thiết với typeof(), nhưng tôi sẽ làm một jsperf và xem nếu ngắn mạch là giá trị nó. – arunjitsingh

1
function checkCallback(cb) 
{ 
    if(cb || cb!='') 
    { 
     if(typeof window[cb] === 'undefined') alert('Callback function not found.'); 
     else window[cb].call(this,Arg1, Arg2); 
    } 
} 
1

bạn có thể xem trong liên kết này tôi thêm cho bạn một ví dụ cơ bản giải thích chức năng gọi lại trong javascript. jsfiddle

var x=0; 

function testCallBack(param1, param2, callback) { 
    alert('param1= ' + param1 + ', param2= ' + param2+' X='+x); 
    if (callback && typeof(callback) === "function") { 
     x+=1; 
     alert("Calla Back x= "+x); 
     x+=1; 
     callback(); 
    } 
} 


testCallBack('ham', 'cheese',function(){ 
alert("Function X= "+x); 
}); 
2

Bạn có thể sử dụng:

if (callback && typeof(callback) === "function") { 
    callback(); 
} 

ví dụ dưới đây rất ít toàn diện hơn:

function mySandwich(param1, param2, callback) { 
alert('Started eating my sandwich.\n\nIt has: ' + param1 + ', ' + param2); 
var sandwich = {toppings: [param1, param2]}, 
    madeCorrectly = (typeof(param1) === "string" && typeof(param2) === "string") ? true : false; 
if (callback && typeof(callback) === "function") { 
    callback.apply(sandwich, [madeCorrectly]); 
    } 
} 

mySandwich('ham', 'cheese', function(correct) { 
if(correct) { 
    alert("Finished eating my " + this.toppings[0] + " and " + this.toppings[1] + " sandwich."); 
} else { 
    alert("Gross! Why would I eat a " + this.toppings[0] + " and " + this.toppings[1] + " sandwich?"); 
    } 
});