オーバーロードされたゲッター/セッター

2011年8月2日

最近JavaScriptをいじっていて、気になったことの一つは、ゲッターとセッターに同じ関数名を使う習慣です。例えば、jQueryでバナーの高さを知りたい場合は、$("#banner").height()を使い、高さを変更したい場合は、$("#banner").height(100)を使います。

この慣習は、Smalltalkでも使われていたので、私にとっては馴染み深いものです。banner heightで値を取得し、banner height: 100で値を変更します。Smalltalkの慣習だと知っていれば、私がこの言語に遠いながらも根強い愛情を持っているため、好きになるだろうと予想できるでしょう。しかし、最良のものにも欠点があり、私はこのコーディングスタイルを嫌いだと隠すことはできません。

私の主な反対意見は、データを取得する行為と値を設定する行為は根本的に異なるため、名前をより明確に区別すべきだということです。[1]

もう一つの理由は、セッターと引数を取るゲッターの間の混乱です。$("#banner").css('height')を見ると、一般的にはCSSプロパティを'height'に設定していると予想します。css('height')が高さの値を取得し、css('height', 100)で更新するということを教えてくれるのは、jQuery APIの知識だけです。

JavaScriptでは、ゲッターとセッターの間の明示性の欠如は、メソッドが1つしかないため、Smalltalkよりも大きくなります。Smalltalkは動的型付け言語ですが、メソッドへの引数の数に基づいてオーバーロードします。[2] JavaScriptは言語内でオーバーロードしないため、ゲッターとセッターは単一のメソッドとして表示されます。ドキュメントは役立ちますが、API自体はそれらを区別していません。追加の引数の存在はFlagArgumentとして機能し、これは通常悪いことです。

Javaの醜いgetHeight() / setHeight(100)の慣習の方が良いと提案しているわけではありません。私は、ゲッターに素の値を使用するのが通常は最善の方法だと考えています。私の好みは、セッターを明確に目立たせることです。

一般的に、私は異なる構文を通じてこれを行うのが好きなので、C#とRubyのプロパティ設定構文がここで最も優れています。これらの言語では、banner.heightで値を取得し、banner.height = 100で値を変更できます。ここでのポイントは、代入の使用が明らかにミューテーションを示すということです。$("#banner").height(100)$("#banner").css('height')の間にあるあいまいさは、ゲッターメソッドでは決して=を使用しないため、発生しません。

ただし、このアプローチは、それをサポートする言語に依存します。JavaScriptではこれを行うことはできません[3]。この場合、私は素のゲッターとプレフィックス付きのセッターを好みます。つまり、banner.height()で値を取得し、banner.setHeight(100)で値を変更します。

この好みにもかかわらず、扱っている言語の慣習に従う必要があります。もし私が再びSmalltalkを書くなら、言語の慣習との一貫性を保つためにheight:100を使い続けるでしょう。しかし、JavaScriptは強力な慣習を持つことで知られているわけではないため、たとえjQueryで使用されていたとしても、私はこの慣習を避けることを好みます。

注記

1: ゲッターとセッターとは、値を取得/設定するように見えるが、UniformAccessPrincipleに従って任意の方法で実装できるメソッドを意味します。

2: 技術的には、'height'と'height:'は(コロンがあるため)異なる名前であるため、オーバーロードではありません。しかし、それは確かにそう感じます。

3: この記事を投稿した後、何人かの人々が、現在いくつかのJavaScript プロパティ 構文があることを指摘しましたが、まだ広く使用されていません。