重载 Getter Setter
2011 年 8 月 2 日
我最近一直在研究 JavaScript,其中一件事让我印象深刻,那就是使用相同的函数名来表示 getter 和 setter 的习惯。因此,如果你想在 jQuery 中找到横幅的高度,你会使用 $("#banner").height()
,如果你想更改高度,你会使用 $("#banner").height(100)
。
这个约定对我来说很熟悉,因为它被 Smalltalk 使用。你可以使用 banner height
获取值,并使用 banner height: 100
更改它。知道它是一个 Smalltalk 约定足以让我期待它,因为我对这种语言有着遥远但持久的热爱。但即使是最好的东西也有缺陷,我无法掩饰我对这种编码风格的厌恶。
我的主要反对意见是,检索数据和设置值的本质是不同的,因此名称应该更加清晰地不同。 [1]
另一个原因是 setter 和带有参数的 getter 之间的混淆。如果我看到 $("#banner").css('height')
,一般的预期是它将 css 属性设置为 'height'。只有我对 jQuery API 的了解告诉我 css('height')
获取高度的值,我将使用 css('height', 100)
来更新它。
JavaScript 中 getter 和 setter 之间的不明确性比 Smalltalk 中更大,因为只有一个方法。Smalltalk 是一种动态类型语言,但会根据方法的参数数量进行重载。 [2] JavaScript 在语言中不进行重载,因此 getter 和 setter 显示为单个方法。文档可以提供帮助,但 API 本身并没有区分它们。额外参数的存在充当 FlagArgument,这通常是一件坏事。
我并不是说 Java 的丑陋 getHeight()
/ setHeight(100)
约定更好。我认为使用裸值作为 getter 通常是最好的方法。我更喜欢让任何 setter 都能清晰地脱颖而出。
一般来说,我喜欢通过不同的语法来做到这一点,因此 C# 和 Ruby 的属性设置语法在这里得分最高。在这些语言中,你可以使用 banner.height
获取值,并使用 banner.height = 100
更改它。这里的重点是,赋值的使用明确地表明了变异。你不会在 $("#banner").height(100)
和 $("#banner").css('height')
之间遇到歧义,因为你永远不会在获取方法中使用 =
。
然而,这种方法取决于支持它的语言。你不能用 JavaScript 做到这一点。 [3] 在这种情况下,我更喜欢使用裸 getter 和带前缀的 setter,因此你可以使用 banner.height()
获取值,并使用 banner.setHeight(100)
更改它。
尽管有这种偏好,但你必须遵循你所使用的语言的约定。如果我再次编写 Smalltalk,我仍然会使用 height:100
来保持与语言约定的 consistency。然而,JavaScript 并没有以拥有强大的约定而闻名,因此在这里我更愿意避免这种约定,即使它被 jQuery 使用。
笔记
1: 我指的是看起来像获取/设置值的 method,但可以以任何方式实现 - 遵循 UniformAccessPrinciple。
2: 从技术上讲,它不是重载,因为 'height' 和 'height:' 是不同的名称(由于冒号)。但它确实感觉像重载。
3: 自从我发布这篇文章以来,有几个人指出现在有一些 javascript property syntaxes,尽管它们还没有被广泛使用。