2012-07-09 67 views
6

Tôi đang cố gắng để quấn quanh đầu của tôi là tại sao mã sau dẫn đến tràn ngăn xếp khi các dấu ngoặc đơn được bao gồm, nhưng không khi chúng bị bỏ qua.Tại sao tôi phải bỏ qua dấu ngoặc đơn khi chuyển một hàm làm đối số?

Tôi đang gọi chính hàm đó làm đối số cho setTimeout và nó hoạt động mà không có dấu ngoặc đơn, nhưng tất nhiên là không thành công khi tôi thêm chúng. Đó là trực giác của tôi để thêm() sau hàm. Chỉ hy vọng ai đó có thể làm rõ điều này cho tôi. Khi nào là parans tùy chọn và không?

TRƯỜNG HỢP 1:

var a = 1; 

function foo() { 
    a++; 
    document.write(a); 
    setTimeout(foo(), 2000) 
}​ 
// RangeError: Maximum call stack size exceeded 

TRƯỜNG HỢP 2:

var a = 1; 

function foo() { 
    a++; 
    document.write(a); 
    setTimeout(foo, 2000) 
}​ 
// parens are omitted on foo function and it works. 
+0

Có thể là một sự lừa đảo. Điều này sẽ giúp: http://stackoverflow.com/questions/5520155/settimeout-callback-argument/5520190#5520190 –

+0

cảm ơn bạn rất nhiều lwburk, lời giải thích của bạn trong liên kết đó đã giải quyết mọi thứ cho tôi. –

Trả lời

9

Câu hỏi này thường được hỏi lần đầu tiên trong tham chiếu đến setTimeout, nhưng tôi nghĩ điều quan trọng là chỉ ra rằng hành vi ở đây không cụ thể với chức năng đó. Bạn chỉ cần hiểu những gì mà dấu ngoặc đơn thực hiện và ý nghĩa của chúng để loại bỏ chúng.

Giả sử hàm sau:

function foo() { 
    return 5; 
} 

Hãy xem xét những điều sau hai biến tờ khai/bài tập:

var one = foo(); 
var two = foo; 

gì giá trị làm các biến này có?

Trong trường hợp đầu tiên chúng tôi thực hiện các foo chức năng và gán giá trị trả về của nó - số 5 - để one. Trong trường hợp thứ hai, chúng tôi đang chỉ định foo chính nó - chính xác hơn, tham chiếu đến foo - đến two. Hàm này không bao giờ được thực hiện.

Với kiến ​​thức này và hiểu rằng setTimeout sẽ là đối số đầu tiên của nó là tham chiếu cho hàm, nên rõ ràng lý do trường hợp đầu tiên của bạn không thành công.

Tất nhiên, vấn đề của bạn càng trở nên trầm trọng hơn bởi thực tế là hàm bạn đang thực hiện là một cuộc gọi đệ quy cho chính nó. Điều này sẽ chỉ chạy mãi mãi - cho một số định nghĩa mãi mãi - bởi vì không có trường hợp cơ sở nào để chấm dứt đệ quy.

+0

câu trả lời tuyệt vời, cảm ơn bạn. –

+0

Tôi phải hỏi bây giờ, nếu bạn muốn tham chiếu hàm foo với đối số thì sao? ví dụ. setTimeout (foo (x), 2000). Tôi hiểu bây giờ rằng điều này rõ ràng sẽ dẫn đến một tràn ngăn xếp, nhưng nó có thể vượt qua một đối số trong tham chiếu hàm đầu tiên? –

+0

@ChrisM - Vâng, trong trường hợp đó, điều tốt nhất cần làm là chuyển một tham chiếu đến một hàm ẩn danh, sau đó gọi hàm mong muốn. Như thế này: 'setTimeout (function() {foo (x)}, 2000)' –

9

Bằng cách viết

foo() 

bạn đang thực sự kêu gọi foo vào lúc đó. Mà tất nhiên sau đó gọi foo() một lần nữa ... cho đến khi bạn stackoverflow.

Trong trường hợp 2 bạn đang chuyển một cách hiệu quả "tham chiếu" sang foo, hãy nói "chạy this in 2s". Không thực sự gọi foo().

Vì vậy, sử dụng parens khi bạn thực sự muốn gọi nó. Không phải khi bạn muốn tham khảo nó.

+0

Ví dụ, thử chạy 'var foo = (function() {alert (" Hello ");})' trong bảng điều khiển của bạn; sau đó, thử chạy 'var foo = (function() {alert (" Hello ");})()' - chú ý cách parens ở cuối câu lệnh thực sự gọi hàm ngay khi nó được định nghĩa! –

+0

điều này có ý nghĩa hoàn hảo với tôi ngay bây giờ. Tôi đã giải thích hai đối số để setTimeout (x, y) là x = bạn muốn làm gì và y = tần suất bạn muốn làm như thế nào. Với sự hiểu lầm của tôi, tôi muốn gọi và thực hiện foo, và cứ làm 2 giây một lần. cảm ơn câu trả lời của bạn! –

Các vấn đề liên quan