Trong JavaScript, nó có tạo ra sự khác biệt nếu tôi gọi một hàm với dấu ngoặc đơn không?


105

Tôi nhận thấy sự khác biệt khi gọi một hàm có dấu ngoặc đơn trống hoặc không có bất kỳ dấu ngoặc đơn nào. Tuy nhiên, tôi không chuyển bất kỳ đối số nào cho hàm nên tôi tự hỏi, sự khác biệt giữa:

window.onload = initAll();

window.onload = initAll;

Hãy giải thích nguyên lý đằng sau nó.


24
@JS Bangs - Chỉ bằng tiếng Anh Mỹ; không phải ở nơi khác. Mặc dù các lập trình viên có xu hướng gọi chúng là "dấu ngoặc" để tránh nhầm lẫn, trong tiếng Anh Anh, những cái được làm tròn được gọi đơn giản là dấu ngoặc. Những hình vuông được gọi là "dấu ngoặc vuông". en.wikipedia.org/wiki/Bracket
Rob Levine

13
một lưu ý nghiêm túc, tên UNICODE chính thức là Dấu ngoặc đơn. 0028 ( LEFT PARENTHESIS = mở ngoặc (1.0) và 0029 ) RIGHT PARENTHESIS = đóng ngoặc (1.0) - unicode.org/charts/charindex.html#P và Dictionary.com nói gì về điều đó - dictionary.reference.com/ Browse / PARENTHESIS "Một hoặc cả hai đường cong thẳng đứng, () ..."

8
Vì vậy, đây không chỉ là một thứ "tiếng Anh Mỹ", nó là một định nghĩa tiêu chuẩn Quốc tế vì UNICODE là một Tiêu chuẩn Quốc tế.

2
@fuzzy - Bạn lấy dữ kiện của mình từ đâu, nghiêm túc vậy? {}được gọi là dấu ngoặc nhọn.
Anurag

7
@fuzzy lollipop - Unicode là một tiêu chuẩn quốc tế về mã hóa các ký tự dưới dạng byte, không phải về cách đặt tên. Các tác giả của tài liệu unicode không khẳng định tên đã cho của một ký tự là tiêu chuẩn quốc tế. Đó là mã so với ký tự mà họ đang xác định. Tuy nhiên, bạn có thể muốn lưu ý rằng chúng cũng đề cập đến [và] dưới dạng dấu ngoặc vuông - (không chỉ "dấu ngoặc") và chúng đề cập đến tất cả [, {và (như các ký tự dấu ngoặc nhọn. Bạn nên cố gắng hiểu các sắc thái trong cách nơi khác nhau sử dụng cùng một từ rất quan trọng nếu bạn là một phần của một nhóm nghiên cứu quốc tế..
Rob Levine

Câu trả lời:


161
window.onload = initAll();

Điều này thực thi initAll() ngay lập tức và gán giá trị trả về của hàm cho window.onload. Đây thường không phải là những gì bạn muốn. initAll()sẽ phải trả về một hàm để điều này có ý nghĩa.

window.onload = initAll;

điều này sẽ gán hàm thực sự cho window.onload- điều này có thể thực hiện được vì trong JavaScript, như @Felix đã nói, các hàm là các đối tượng lớp đầu tiên - mà không cần thực thi nó. initAllsẽ được thực thi bởi sự kiện tải.


18
Điều quan trọng cần đề cập ở đây là các hàm là các đối tượng hạng nhất trong JavaScript.
Felix Kling

136

Những gì Pekka nói là đúng, nhưng tôi muốn giải thích thêm một chút với một ví dụ sẽ giúp giải thích cho những người không hiểu đầy đủ về con trỏ hoặc đại biểu hàm.

Tôi sẽ không sử dụng window.onloadbởi vì đó là một chút giả thiết để chứng minh. Thay vào đó, tôi sẽ sử dụng một hàm nhân đơn giản để demo:

function Multiply(operator, operand) {
    return operator * operand;
}

Điều này cũng có thể được viết:

Multiply = function(operator, operand) {
    return operator * operand;
}

Mặc dù trong ví dụ đầu tiên, hàm ý có thể không rõ ràng, nhưng ví dụ thứ hai cho thấy rõ ràng hơn rằng chúng ta đang gán một hàm có 2 tham số cho một biến được gọi Multiplyvà khái niệm hàm dưới dạng phép gán này là phổ biến trong JavaScript. Đây là một minh chứng nhỏ về thực tế rằng các hàm là "công dân hạng nhất" , nghĩa là, chúng có thể được truyền xung quanh chính xác như thể chúng ta truyền xung quanh các giá trị.

Vì vậy, bây giờ đến sự khác biệt của nhiệm vụ:

var operator = 3;
var operand = 4;
var ret = Multiply(operator, operand);

Tại điểm xác định biến ret, Multiplyđược thực thi và giá trị trả về được gán - rettrở thành bằng 12.

Hãy thử lại theo cách khác:

var operator = 3;
var operand = 4;
var ret = Multiply;

Bây giờ, tại điểm xác định ret, rettrở thành Multiplyhàm của bạn thay vì là kết quả thu được từ Multiplyhàm của bạn . Các lệnh gọi tới ret()sẽ khiến Multiplyhàm của bạn được thực thi và bạn có thể gọi nó chính xác như thể bạn đã gọi Multiply(operator, operand):

var out = ret(3, 4);

giống như

var out = Multiply(3, 4);

Bạn đã nói một cách hiệu quả rằng bạn sẽ sử dụng retnhư một đại biểu cho Multiply(). Khi gọi ret, chúng tôi thực sự đang đề cập đến Multiplyhàm.

Trở lại của bạn window.onload. Hãy nghĩ về điều này như:

window.onload = function() {
    //Doing what all good window.onload functions should do...
}

initAll = function() {
    return 12;
}

Vì vậy, như bạn có thể thấy, window.onloadlà một chức năng giống như bất kỳ chức năng nào khác, không có gì đặc biệt về nó. Bạn có thể gán cho nó một giá trị, gán cho nó một chức năng, vô hiệu hóa nó nếu bạn muốn - vấn đề là không có gì đặc biệt window.onloadhơn là về chức năng của riêng bạn. Điều duy nhất hơi khác là nó được gọi bởi cửa sổ khi nó được tải. [Tuyên bố từ chối trách nhiệm: Tôi chưa bao giờ thực sự hủy bỏ các chức năng cửa sổ, vì vậy tôi không chắc liệu điều này có gây ra hậu quả tiêu cực hay không. Người ta hy vọng họ sẽ kiểm tra xem một hàm có được gán hay không trước khi gọi nó tức là if (window.onload) window.onload();].

Bây giờ gọi initAll()những gì chúng ta đang nói là:

window.onload = initAll();

cũng có thể nói:

window.onload = 12;

Nhưng khi chúng ta nói initAllmà không có dấu ngoặc đơn, điều chúng ta thực sự đang nói là: Tôi muốn thay thế bất kỳ hàm window.onload của tôi là gì, bằng một hàm mới - tức là tôi muốn thay thế nó bằng initAllhàm của mình , để mọi lệnh gọi window.onloadchạy initAllmã.

Vì thế:

window.onload = function() {
    //Doing what all good window.onload functions should do...
}

được thay thế bằng:

window.onload = function() {
    return 12;
}

Vì vậy, bất kỳ lệnh gọi nào window.onloadsẽ thực thi initAllchức năng của bạn thay vì bất kỳ lệnh nào window.onloadban đầu. Bạn đã thay thế chức năng ban đầu bằng chức năng mới của mình.

Trên thực tế, bạn có thể viết:

window.onload = function() {
    //Write all your init code right in here instead of having a separate 
    //initAll function.
}

Một ví dụ khác có thể chứng minh tốt hơn là:

var d = new Date();
var currentTime = d.getTime();

Bất kể thời gian là tại thời điểm dđược xác định cuối cùng sẽ được gán cho currentTime. Tuyệt vời, nhưng điều đó chỉ hữu ích nếu chúng ta muốn tìm hiểu thời gian hàm chứa mã đó được gọi - tức là tại thời gian tải trang. Điều gì sẽ xảy ra nếu chúng ta muốn thời gian hiện tại bất kỳ lúc nào currentTimeđược gọi?

var currentTime = function() {
    var d = new Date();
    return d.getTime();
}

var a = currentTime(); //The current time at the point a is defined...
var b = currentTime;   //b is a functional reference to currentTime...
var c = b(); //The current time when variable c is defined
var d = c; //The current time when variable c was defined

Chú ý cách chúng ta gọi b()trong bài tập cvà của mình dchính xác như cách chúng ta có thể gọi currentTime()?


Câu trả lời tuyệt vời!
Shadi Almosri

Này, nếu tôi muốn thêm một hàm nhận đối số trên trình xử lý sự kiện thì sao?
Shemiroth

16

Các hàm trong javascript là công dân hạng nhất và như vậy, có thể được gán cho các biến khác hoặc được chuyển xung quanh dưới dạng đối số.

Vì vậy, khi bạn làm

window.onload = initAll;

Bạn đang đặt thuộc onloadtính của windowđối tượng để tham chiếu initAllchính hàm.

Khi bạn làm

window.onload = initAll();

Bạn đang đặt thuộc onloadtính để giữ giá trị trả về của initAll, vì nó sẽ thực thi ở vị trí trên dòng đó.


10

initAll là một tham chiếu đến một giá trị hàm và toán tử dấu ngoặc được thêm vào tên hàm RUNS đối tượng hàm này.

Vì vậy, nếu bạn làm điều gì đó như

a = initAll

sau đó asẽ giống như initAll- ví dụ bạn có thể làm a()- nhưng với

a = initAll()

biến asẽ nhận giá trị trả về của initAllhàm được thực thi


8

Tôi đã muộn 6 năm nhưng tôi cảm thấy điều này có thể được giải thích đơn giản hơn rất nhiều so với các câu trả lời trên.

Vì vậy, đây là TLDR ; hoặc xem mắt chim khi gọi chức năng sử dụng và không sử dụng ()'s

Hãy lấy chức năng này làm ví dụ:

function foo(){
return 123;
}

nếu bạn đăng nhập "foo" - không có ()

console.log(foo); 

---outout------
function foo(){
return 123;
}

Không sử dụng ()phương tiện nào để tìm nạp chính hàm . Bạn sẽ làm điều này nếu bạn muốn nó được chuyển cùng như một cuộc gọi lại.


nếu bạn đăng nhập "foo ()" - với ()

console.log(foo());
-----output-----
 123

Sử dụng ()sau một hàm nghĩa là thực thi hàm và trả về giá trị của nó .

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.