2010-09-19 36 views
5

Một trong những lỗi phổ biến nhất của tôi là tôi không bao giờ có thể nhớ liệu một cái gì đó là một phương pháp hay một tài sản, vì vậy tôi liên tục thêm hoặc loại bỏ dấu ngoặc đơn.Tại sao java/javascript/python buộc sử dụng() sau tên phương thức, ngay cả khi nó không có đối số?

Vì vậy, tôi đã tự hỏi nếu có logic tốt đằng sau việc tạo sự khác biệt giữa việc gọi các thuộc tính và phương thức của đối tượng một cách rõ ràng.

Rõ ràng, nó cho phép bạn có các thuộc tính và phương thức chia sẻ cùng một tên, nhưng tôi không nghĩ rằng nó xuất hiện nhiều.

Lợi ích lớn duy nhất tôi có thể đưa ra là dễ đọc. Đôi khi bạn có thể muốn biết liệu một cái gì đó là một phương pháp hay một tài sản trong khi bạn đang nhìn vào mã, nhưng tôi gặp khó khăn khi đưa ra các ví dụ cụ thể khi điều đó thực sự hữu ích. Nhưng tôi là một n00b, nên có lẽ tôi chưa gặp phải tình huống như vậy. Tôi đánh giá cao các ví dụ về tình huống như vậy.

Ngoài ra, có các ngôn ngữ khác mà sự khác biệt không rõ ràng không?

Dù sao, nếu bạn có thể trả lời, nó sẽ giúp tôi bớt khó chịu mỗi lần tôi phạm sai lầm này^- ^.

CẬP NHẬT: Cảm ơn tất cả mọi người về câu trả lời tuyệt vời cho đến nay! Tôi chỉ có giá trị của một tuần của js, và 1 ngày của python, vì vậy tôi không có ý tưởng bạn có thể tham khảo các chức năng mà không cần gọi chúng. Thật tuyệt vời. Tôi có một chút kinh nghiệm với java, vì vậy đó là nơi tôi chủ yếu đến từ ... bất cứ ai có thể đưa ra một đối số hấp dẫn không kém cho rằng đó là trường hợp trong java, nơi bạn không thể tham chiếu các chức năng? Bên cạnh đó là một ngôn ngữ rất rõ ràng, với tất cả những lợi ích đòi hỏi :).

+0

không đòi hỏi phải có '()', vì bạn đang nói trình biên dịch và người xem tương lai mã của bạn, "Đây là hàm, không yêu cầu tham số." Rõ ràng luôn tốt hơn là ngầm. – orokusaki

Trả lời

1

Thông thường thuộc tính là người truy cập và các phương pháp thực hiện một số loại hành động. Đi trên giả định này, nó rẻ để sử dụng một tài sản, đắt tiền để sử dụng một phương pháp. Ví dụ:

Ví dụ: Foo.Bar sẽ cho tôi biết rằng nó sẽ trả về một giá trị, như một chuỗi, không có nhiều chi phí.

Foo.Bar() (hoặc nhiều khả năng, Foo.GetBar()), mặt khác, ngụ ý cần truy xuất giá trị cho "Bar", có lẽ từ cơ sở dữ liệu.

Thuộc tính và phương pháp có mục đích khác nhau và các tác động khác nhau, vì vậy chúng cũng phải được phân biệt trong mã.

Bằng cách này, trong tất cả các ngôn ngữ tôi biết về sự khác biệt về cú pháp là rõ ràng, nhưng đặc tính đằng sau hậu trường thường được coi là các cuộc gọi phương thức đặc biệt đơn giản.

+1

Tôi đồng ý rằng các truy cập giống như tài sản phải rẻ, nhưng tôi không đồng ý với một nửa còn lại; rất nhiều chức năng rất rẻ để gọi. –

+0

Không phủ nhận điều đó, nhưng đây là cuộc thảo luận về sự so sánh của * cùng một phương thức */thuộc tính với * cùng tên * - bạn sẽ mong đợi có nhiều chi phí hơn? – jvenema

+0

Tôi mong đợi một người khởi xướng (ví dụ: GetX) có triển khai khá rẻ. Tôi không thấy rằng nó ngụ ý cần phải lấy lại giá trị. Hầu hết các getters tôi đã nhìn thấy chỉ đơn giản là trả lại một thuộc tính. –

3

Tôi nghĩ rằng bạn đã trả lời nó tự hỏi:

Một trong những lỗi phổ biến nhất của tôi là tôi không bao giờ có thể nhớ một cái gì đó dù là một phương pháp hay một tài sản, vì vậy tôi liên tục bổ sung hoặc loại bỏ các dấu ngoặc đơn.

xem xét như sau:

if (colorOfTheSky == 'blue')

vs:

if (colorOfTheSky() == 'blue')

Chúng tôi có thể nói chỉ cần nhìn mà kiểm tra đầu tiên cho một biến gọi là colorOfTheSky, và chúng tôi muốn biết nếu giá trị của nó là blue. Trong lần thứ hai, chúng ta biết rằng colorOfTheSky() gọi một hàm (phương thức) và chúng ta muốn biết giá trị trả về của nó là blue hay không.

Nếu chúng tôi không có sự khác biệt này, nó sẽ vô cùng mơ hồ trong các tình huống như thế này.

Để trả lời câu hỏi cuối cùng của bạn, tôi không biết bất kỳ ngôn ngữ nào không có sự khác biệt này.

Ngoài ra, bạn có thể có vấn đề về thiết kế nếu bạn không thể biết sự khác biệt giữa các phương pháp và thuộc tính của bạn; như một câu trả lời chỉ ra, phương pháp và tài sản có vai trò khác nhau để chơi. Hơn nữa, thực tiễn tốt cho tên phương thức của bạn là hành động, ví dụ: getPageTitle, getUserId, v.v., và cho thuộc tính của bạn là danh từ, ví dụ: pageTitle, userId. Những mã này phải dễ dàng giải mã được trong mã của bạn cho cả bạn và bất kỳ ai đến sau và đọc mã của bạn.

+0

Điều này không chính xác trong Python đối với tên phương thức (không phải tên hàm trống), 'foo.colorOfTheSky' là một hàm gọi nếu' colorOfTheSky' là thuộc tính. điều này nói chung, nhưng sẽ rất hữu ích nếu bạn cần cung cấp thông tin cụ thể trong terface cho thấy các thuộc tính của lớp nhưng cần phải thực hiện nó với các cuộc gọi hàm đằng sau hậu trường. –

+0

@Glenn: Không biết điều đó; Cảm ơn bạn về thông tin. –

5

Ít nhất là trong JS, bởi vì bạn có thể truyền các chức năng xung quanh.

var func = new Function(); 

bạn có thể sau đó nên cái gì như

var f = func 
f() 

để 'f' và 'func' là tài liệu tham khảo cho các chức năng, và f() hoặc Func() là gọi của hàm.

đó là không giống như

var val = f(); 

đó gán kết quả của sự thỉnh nguyện đến một var.

Đối với Java, bạn không thể chuyển các hàm xung quanh, ít nhất là bạn có thể trong JS, vì vậy không có lý do nào ngôn ngữ cần yêu cầu() để gọi phương thức. Nhưng đó là những gì nó được.

Tôi không thể nói gì cả cho python.

Nhưng điểm chính là các ngôn ngữ khác nhau có thể có lý do tại sao cú pháp có thể cần thiết và đôi khi cú pháp chỉ là cú pháp.

13

Tất cả các ngôn ngữ hiện đại yêu cầu điều này vì tham chiếu một hàm và gọi một chức năng là các hành động riêng biệt.

Ví dụ,

def func(): 
    print "hello" 
    return 10 
a = func 
a() 

Rõ ràng, a = funca = func() có ý nghĩa rất khác nhau.

Ruby - ngôn ngữ có khả năng nhất mà bạn đang nghĩ ngược lại - không yêu cầu dấu ngoặc đơn; nó có thể làm điều này bởi vì nó không hỗ trợ tham chiếu đến các hàm.

+3

Lý do tại sao Ruby không hỗ trợ tham chiếu đến các hàm, bởi vì nó là một ngôn ngữ hướng đối tượng, và do đó không * có * chức năng. Nó có, tuy nhiên, có * phương pháp * và nó * không * hỗ trợ tham chiếu đến phương pháp. –

+15

Bạn luôn có thể tin tưởng vào Rubyites sắp ra khỏi bụi cây với bất kỳ gợi ý nào về ngôn ngữ của họ, thường là với một nỗ lực vẹt để xác định lại từ "hàm". –

+1

@Juan Pablo Califano: tính năng chính của một chức năng là nó không thể có bất kỳ tác dụng phụ. Phương pháp của Ruby * có thể * có tác dụng phụ, do đó chúng không thể hoạt động. –

8

Trong các ngôn ngữ như Python và JavaScript, hàm là đối tượng hạng nhất. Điều này có nghĩa là bạn có thể truyền các hàm xung quanh, giống như bạn có thể truyền xung quanh bất kỳ giá trị nào khác. Các dấu ngoặc đơn sau tên hàm (số () trong myfunc()) thực sự cấu thành toán tử, giống như + hoặc *. Thay vì ý nghĩa "thêm số này vào một số khác" (trong trường hợp +), () có nghĩa là "thực hiện chức năng trước". Điều này là cần thiết bởi vì nó có thể sử dụng một hàm mà không thực hiện nó. Ví dụ, bạn có thể muốn so sánh nó với chức năng khác sử dụng ==, hoặc bạn có thể muốn vượt qua nó vào chức năng khác, chẳng hạn như trong ví dụ này JavaScript:

function alertSomething(message) { 
    alert(message); 
} 

function myOtherFunction(someFunction, someArg) { 
    someFunction(someArg); 
} 

// here we are using the alertSomething function without calling it directly 
myOtherFunction(alertSomething, "Hello, araneae!"); 

Tóm lại: điều quan trọng là để có thể đề cập đến một chức năng mà không cần gọi nó - đây là lý do tại sao sự khác biệt là cần thiết.

+0

Ồ, tôi không biết bạn có thể làm điều đó! Đó là một ví dụ thực sự tuyệt vời. – araneae

2

Vì việc tham chiếu và gọi phương thức là hai điều khác nhau. Hãy xem xét X.method là phương pháp class Xx là một thể hiện của X, vì vậy x.method == 'blue' sẽ không bao giờ có thể đúng vì các phương thức không phải là chuỗi.

Bạn có thể thử này: in một phương pháp của một đối tượng:


>>> class X(object): 
... def a(self): 
...  print 'a' 
... 
>>> x=X() 
>>> print x.a 
<bound method X.a of <__main__.X object at 0x0235A910>> 

3

Nếu bạn gặp rắc rối, phân biệt giữa tài sản và phương pháp của bạn, có lẽ bạn đang không đặt tên cho chúng rất tốt.

Nói chung, các phương pháp của bạn nên có động từ trong chúng: tức là viết, in, echo, mở, đóng, lấy, đặt và tên thuộc tính phải là danh từ hoặc tính từ: tên, màu, đầy, được tải.

Điều rất quan trọng là sử dụng các tên thuộc tính và phương thức có ý nghĩa, không có tên, bạn sẽ thấy rằng bạn sẽ gặp khó khăn khi đọc mã của riêng mình.

+0

Nó thực sự thường là một vấn đề với những thứ tôi không nêu tên. Ví dụ, để sử dụng một đối tượng TreeWalker, lastChild() là một phương thức nhưng currentNode là một thuộc tính. Tôi đoán khi nào nó có ý nghĩa là vị trí hiện tại sẽ được lưu trữ, nhưng nó không rõ ràng rằng đứa trẻ cuối cùng sẽ không được. Và những gì về obj.length, hoặc obj.length()? Trong JS, chiều dài là một thuộc tính của một chuỗi nhưng trong java nó là một phương pháp ... có lẽ nó NÊN được getLength() nhưng nó không phải là: P – araneae

+0

Nếu nó là một phương pháp nó ngụ ý rằng bộ xử lý thực hiện một phép tính để trả về một giá trị, nếu nó là một thuộc tính thì nó đơn giản là một giá trị nhận được từ RAM. Ví dụ, currentNode được lưu trữ và lấy ra, trong khi cho lastChild được trả về, trước tiên bộ xử lý phải xác định số phần tử trong nút, sau đó trả về giá trị cuối cùng, vì vậy giá trị của lastChild không được lưu trữ trong bộ nhớ, nhưng được tính khi cần thiết. Giống như obj.length [()], javascript lưu trữ giá trị, trong khi java tính toán nó. –

+0

Phải. Tôi hiểu sự khác biệt, tôi đã chỉ ra rằng trong hai ví dụ đó, tên phương thức không có động từ trong chúng (lastChild() và length()) và đó là mã tôi không viết. – araneae

2

Trong Java, tôi có thể nghĩ đến hai lý do tại sao () được yêu cầu:

1) Java đã có một mục tiêu thiết kế cụ thể để có một "C/C++ như" cú pháp, để làm cho nó dễ dàng cho C và C++ lập trình để học ngôn ngữ. Cả C và C++ đều yêu cầu dấu ngoặc đơn.

2) Cú pháp Java yêu cầu cụ thể các dấu ngoặc đơn để phân biệt một tham chiếu đến một thuộc tính hoặc cục bộ từ một cuộc gọi đến một phương thức. Điều này là do tên phương thức và thuộc tính/tên cục bộ được khai báo trong các không gian tên khác nhau. Vì vậy, sau đây là Java pháp lý:

public class SomeClass { 
    private int name; 
    private int name() { ... } 

    ... 

    int norm = name; // this one 
} 

Nếu () không cần thiết cho một lời gọi phương thức, trình biên dịch sẽ không có thể cho biết nếu báo cáo kết quả được dán nhãn ("cái này") được gán giá trị của name thuộc tính hoặc kết quả của việc gọi phương thức name().

+0

Tôi nghi ngờ # 1 là lý do Java là như thế này; đó là một ngôn ngữ rất rõ ràng. # 2 chỉ ra rằng các phương thức và các biến có thể có cùng tên trong java. Hiệu ứng không quan trọng (imo) của việc loại bỏ() có thể là bạn đơn giản sẽ phải có tên duy nhất cho các phương thức và các trường.Tôi đang tìm cái gì đó thảm khốc hơn; chắc chắn không gian tên trong java là một chút phức tạp, những gì với thừa kế và tất cả; có lẽ có thể có những hậu quả không mong muốn (hoặc ít nhất là những khó khăn cho trình biên dịch để làm việc xung quanh) với điều đó? – araneae

+0

@araneae - cũng có thể có các lý do khác. Nhưng câu hỏi là tranh luận. Java là Java. Một cái gì đó cơ bản như thế này sẽ không thay đổi. –

2

Sự khác biệt không phải lúc nào cũng rõ ràng trong VBA. Đây là một cuộc gọi đến một Tiểu (tức làmột phương pháp không có giá trị trả về) mà mất không có thông số (tất cả các ví dụ là từ Excel):

Worksheets("Sheet1").UsedRange.Columns.AutoFit 

trong khi điều này được truy cập vào một thuộc tính sau đó đi qua nó như một tham số:

MsgBox Application.Creator 

Như trong trước Ví dụ, dấu ngoặc đơn cũng là tùy chọn xung quanh các thông số nếu không có nhu cầu để đối phó với giá trị trả về:

Application.Goto Worksheets("Sheet2").Range("A1") 

nhưng là cần thiết nếu giá trị trả về được sử dụng:

iRows = Len("hello world") 
Các vấn đề liên quan