JavaScriptではオブジェクトにあらかじめ定義されているメソッドがあり、これらはオーバーライド(上書き定義)できる。これ自体が素晴らしくプロジェクトに貢献するわけではないが、JavaScriptの性質を抑えておけば、より便利にカスタムオブジェクトを扱うことができるかもしれない。

valueOf()

これはJavaScriptのオブジェクトに標準で存在するメソッドで、オーバーライド可能である。既定の挙動は this を返すものだが、MDNのリファレンスではプリミティブ値を返すことを期待している。しかし、this を返すことから、オブジェクトは平然とオブジェクトを返すというルール違反をしている。

このメソッドの挙動は少々捉えにくいが、「プリミティブ値としての挙動を要求されたときに暗黙的に呼び出される」ということである。前に挙げたDateオブジェクトのクローンを作る例を再掲するが:

const a = new Date()
const b = new Date(a)

これは暗黙的に a.valueOf() が呼び出されている。1引数でDateコンストラクタを呼び出すと、UNIXタイムスタンプからオブジェクトを作るが、このときに値がnumberであることが要求される。与えられた値はオブジェクトにも関わらず、Dateオブジェクトの valueOf() はUNIXタイムスタンプを数値として返すので、この式は正しく動く。さらにこの特性を利用すれば:

const a = new Date() * 1
const b = +new Date()

も正しいことがわかる。これは getTime() を短く書くためのテクニックのひとつだ。

もし特定のオブジェクトに対してプリミティブ値としての振舞いも持たせたいのであれば、valueOf() を定義すると取り回しがよくなるし、逆にプリミティブ値としての動作をさせたくないのであれば、エラーが出るようにしてもいいだろう。

toString()

このメソッドをオーバーロードしないと、多くのオブジェクトは文字列に変換したときに [Object object] になる。console.log() で直接オブジェクトを指定したときには中身を確認できるが、文字列と連結したり、テンプレートリテラルを使用したりするときには期待した動作にはならない。

小さなオブジェクトであれば、適切な文字列表現を得るためのメソッドとして機能するだろうし、集約オブジェクトのような大きい概念になってくれば、デバッグ出力のための便利関数になると思われるので、必要であれば実装しておくとあとになって役に立つかもしれない。