【问题标题】:Why does java/javascript/python force the use of () after a method name, even if it takes no arguments?为什么 java/javascript/python 强制在方法名称后使用 (),即使它不带参数?
【发布时间】:2011-04-14 05:42:06
【问题描述】:

我最常见的错误之一是我永远不记得某个东西是方法还是属性,所以我不断地添加或删除括号。

所以我想知道在明确调用对象的属性和方法之间是否存在良好的逻辑。

显然,它允许您拥有共享相同名称的属性和方法,但我认为这种情况并不多。

我能想到的唯一大好处是可读性。有时您在查看代码时可能想知道某个东西是方法还是属性,但是当这真的很有帮助时,我很难想出具体的例子。但是我是n00b,所以我可能还没有遇到过这种情况。我会很感激这种情况的例子。

另外,还有其他语言没有明确的区别吗?

无论如何,如果你能回答,我每次犯这个错误时都会减少烦恼^-^。

更新: 感谢大家到目前为止的精彩答案!我只有大约一周的 js 和 1 天的 python,所以我不知道你可以在不调用函数的情况下引用函数。棒极了。我对 java 有更多的经验,所以这就是我主要来自的地方......谁能想出一个同样令人信服的论点来证明在 java 中的情况,你不能引用函数?除了它是一种非常明确的语言之外,它还具有所需要的所有好处:)。

【问题讨论】:

  • 它并不需要(),因为它是在告诉编译器和代码的未来查看者,“这是一个函数,它需要零参数。”。显式总比隐式好。

标签: java javascript python methods properties


【解决方案1】:

所有现代语言都要求这样做,因为引用一个函数和调用一个函数是独立的动作。

例如,

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

显然,a = funca = func() 的含义截然不同。

Ruby——相比之下,您最有可能想到的语言——不需要括号;它可以这样做,因为它不支持对函数的引用。

【讨论】:

  • Ruby 之所以不支持引用函数,是因为它是一种面向对象的语言,因此没有具有函数。但是,它确实有方法,而且它确实支持引用方法。
  • 你总是可以指望 Rubyites 从灌木丛中走出来,只要有任何批评他们的语言的迹象,通常都是鹦鹉学舌地尝试重新定义“函数”这个词。
  • @Juan Pablo Califano:函数的主要特点是它不能有任何副作用。 Ruby 的方法可以有副作用,因此它们不能是函数。
  • @Jörg W Mittag。我不同意。让我们以 C 语言为例,它无疑是一种具有功能的语言。这些函数肯定会产生副作用(有时甚至是非常丑陋的)。
  • @Jörg:这个定义在函数式编程语言中可能是正确的,但它不是“函数”在诸如 Python、Javascript、Java、C++、PHP、Perl 等过程编程语言中的含义开。
【解决方案2】:

在 Python 和 JavaScript 等语言中,函数是一流的对象。这意味着您可以传递函数,就像您可以传递任何其他值一样。函数名后面的括号(myfunc() 中的())实际上构成了一个运算符,就像+* 一样。 () 的意思不是“将此数字添加到另一个数字”(在+ 的情况下),而是表示“执行前面的函数”。这是必要的,因为可以在不执行函数的情况下使用它。例如,您可能希望使用 == 将其与另一个函数进行比较,或者您可能希望将其传递给另一个函数,例如在这个 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!"); 

简而言之:能够在不调用函数的情况下引用它是很重要的——这就是为什么区分是必要的。

【讨论】:

  • 哇哦,我不知道你能做到这一点!这是一个非常好的例子。
【解决方案3】:

至少在 JS 中,因为你可以传递函数。

var func = new Function();

然后你可以这样

 var f = func
 f()

所以 'f' 和 'func' 是对函数的引用,而 f() 或 func() 是函数的调用。

不一样的

var val = f();

将调用的结果分配给一个变量。

对于 Java,您不能传递函数,至少就像在 JS 中一样,因此该语言没有理由需要 () 来调用方法。但事实就是如此。

我根本不会说python。

但重点是不同的语言可能有理由说明为什么需要语法,有时语法就是语法。

【讨论】:

    【解决方案4】:

    我想你自己回答了:

    我最常见的错误之一是我永远记不起某个东西是方法还是属性,所以我不断地添加或删除括号。

    考虑以下几点:

    if (colorOfTheSky == 'blue')

    对比:

    if (colorOfTheSky() == 'blue')

    我们可以通过查看第一个检查名为colorOfTheSky 的变量来判断,我们想知道它的值是否为blue。第二,我们知道colorOfTheSky()调用了一个函数(方法),我们想知道它的返回值是不是blue

    如果我们没有这种区别,在这种情况下就会非常模糊。

    回答你的最后一个问题,我不知道任何语言没有这种区别。

    此外,如果您无法区分方法和属性,则可能存在设计问题;正如另一个答案指出的那样,方法和属性扮演着不同的角色。此外,将方法名称作为操作是一种很好的做法,例如getPageTitlegetUserId 等,并将您的属性设为名词,例如 pageTitleuserId。对于您和后来出现并阅读您的代码的任何人,这些都应该在您的代码中很容易被破译。

    【讨论】:

    • 这在 Python 中对于方法名称(不是裸函数名称)是不正确的;如果colorOfTheSky 是一个属性,则foo.colorOfTheSky 是一个函数调用。总的来说,我对此并不感到疯狂,但如果您需要提供一个特定的接口来公开类属性但需要在后台使用函数调用来实现它,这将很有帮助。
    【解决方案5】:

    如果您在区分属性和方法时遇到问题,您可能没有很好地命名它们。

    一般来说,你的方法应该有一个动词:即 write、print、echo、open、close、get、set 和属性名称应该是名词或形容词:名称、颜色、填充、加载。

    使用有意义的方法名和属性名非常重要,没有它,你会发现你将难以阅读自己的代码。

    【讨论】:

    • 这实际上通常是我没有命名的问题。例如,要使用 TreeWalker 对象,lastChild() 是一个方法,而 currentNode 是一个属性。我想什么时候存储当前位置是有意义的,但最后一个孩子不会被存储并不明显。那么 obj.length 或 obj.length() 呢?在 JS 中,长度是字符串的属性,但在 java 中,它是一种方法......也许它应该是 getLength() 但它不是:P
    • 如果它是一个方法,则暗示处理器进行计算以返回一个值,如果它是一个属性,那么它只是一个从 RAM 中检索的值。例如,currentNode 是存储和检索的,而要返回 lastChild,处理器必须先确定节点中的元素个数,然后返回最后一个值,因此 lastChild 的值不存储在内存中,而是在计算时计算需要。和obj.length[()]一样,javascript存储值,java计算。
    • 对。我理解其中的区别,我只是指出,在这两个示例中,方法名称中没有动词(lastChild() 和 length()),这是我自己编写的代码。
    • 在 Python 和 JavaScript 中,您可以让函数像属性一样可访问,而不是使用 get* 和 set* 方法。有关 JavaScript,请参阅 ejohn.org/blog/javascript-getters-and-setters,对于 Python,请参阅 adam.gomaa.us/blog/2008/aug/11/the-python-property-builtin
    【解决方案6】:

    在 Java 中,我可以想到为什么需要 () 的两个原因:

    1) Java 有一个特定的设计目标,即拥有“类似 C/C++”的语法,以便 C 和 C++ 程序员轻松学习该语言。 C 和 C++ 都需要括号。

    2) Java 语法特别需要括号来区分对属性的引用或对方法的调用的本地引用。这是因为方法名称和属性/本地名称是在不同的命名空间中声明的。所以下面是合法的Java:

    public class SomeClass {
        private int name;
        private int name() { ... }
    
        ...
    
        int norm = name;  // this one
    }
    

    如果方法调用不需要(),编译器将无法判断标记语句(“this one”)是分配name属性的值还是调用name() 方法。

    【讨论】:

    • 我怀疑 #1 是 Java 是这样的原因;这是一种非常明确的语言。 #2 解决了方法和变量在 java 中可以具有相同名称的事实。消除 () 的无关紧要的 (imo) 效果就是您只需要为方法和字段提供唯一的名称。我正在寻找更具灾难性的东西;当然,java中的命名空间有点复杂,继承等等;也许会有意想不到的后果(或者至少是编译器难以解决的后果)?
    • @araneae - 很可能还有其他原因。但这个问题没有实际意义。 Java就是Java。像这样基本的东西不会改变。
    【解决方案7】:

    区别在 VBA 中并不总是明确的。这是对不带参数的 Sub(即没有返回值的方法)的调用(所有示例均来自 Excel):

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

    而这是访问一个属性,然后将其作为参数传递:

    MsgBox Application.Creator
    

    和前面的例子一样,如果不需要处理返回值,括号也是可选的:

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

    但如果使用返回值则需要:

    iRows = Len("hello world")
    

    【讨论】:

      【解决方案8】:

      因为引用和调用方法是两件不同的事情。考虑X.methodclass X 的方法,xX 的一个实例,所以x.method == 'blue' 永远不可能为真,因为方法不是字符串。

      你可以试试这个:打印一个对象的方法:

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

      【讨论】:

        【解决方案9】:

        通常,属性是访问器,方法执行某种操作。按照这个假设,使用属性很便宜,使用方法很昂贵。

        例如,Foo.Bar 会告诉我它会返回一个值,就像一个字符串,而不会产生很多开销。

        另一方面,Foo.Bar()(或更可能是 Foo.GetBar())意味着需要从数据库中检索“Bar”的值。

        属性和方法有不同的用途和不同的含义,因此在代码中也应该加以区分。

        顺便说一句,在我所知道的所有语言中,语法差异是明确的,但在幕后属性通常被视为简单的特殊方法调用。

        【讨论】:

        • 我同意类似属性的访问应该便宜,但我不同意另一半;很多函数调用起来都很便宜。
        • 不否认这一点,但这是对 same 方法/属性与 same 名称的比较的讨论 - 您希望有更多开销?
        • 我希望 getter(即 GetX)有一个相当便宜的实现。我不认为这意味着需要检索该值。我见过的大多数 getter 只是返回一个属性。
        • @Winston:在将Beads 移植到 JavaScript(Beads.js,由于代码的循环和高性能特性,getter 会减慢一点;删除所有琐碎的 getter 并使用这些属性直接产生了非常显着的性能优势(我记得大概是 20-30%)。
        • @Chris Morgan,这里的问题是关于你期望像 GetFoo() 这样的函数做什么。我希望 GetFoo() 相对于 CalculateFoo() 来说便宜。现在,如果你想变得非常快,那么即使是简单的 GetFoo() 函数也可能对你来说不够快。这似乎是你的情况。
        猜你喜欢
        • 2017-03-24
        • 2017-01-24
        • 2018-10-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多