JavaScriptでは、クラスをnew
して作ったオブジェクトを.toString()
しても'[object Object]'
が戻り値になる。
この戻り値を、デコレーターを用いて[object クラス名]
に変える方法を紹介する。
Object.prototype.toString
を上書きする必要はない
通常、コンストラクタが返す値は、Object
を継承しているので、toString
メソッドが生えている。toString
の結果を変えようとするなら、Object.prototype.toString
をオーバーライドする方法が思いつくが、その必要はない。Object.prototype.toString
が[object Object]
を返すのはデフォルトの振る舞いで、この戻り値のObject
の部分だけを変更する仕組みがあるからだ。
Symbol.toStringTag
を使う
オブジェクトに[Symbol.toStringTag]
プロパティがあると、Object.prototype.toString
は"Object"
よりも、そのプロパティの値を尊重してくれる。
class Foo { } // 通常のクラス
class Bar {
[Symbol.toStringTag] = 'Bar'
}
console.log(new Foo().toString()) //=> [object Object]
console.log(new Bar().toString()) //=> [object Bar]
参考: Symbol.toStringTag - JavaScript | MDN
Symbol.toStringTag
をデコレータで実現する
クラスごとに[Symbol.toStringTag]
を実装するのは面倒なので、デコレータで実現する方法を紹介する。
次のコードのautotag
はクラスデコレータの実装で、デコレートされたクラスに[Symbol.toStringTag]
プロパティを生やす。
// デコレータの定義
const autotag: ClassDecorator = constructor => {
constructor.prototype[Symbol.toStringTag] = constructor.name
return constructor
}
使い方としては、クラスの手前に@autotag
と書くだけ。これで、クラスに[Symbol.toStringTag]
を実装したのと同じ効果が得られる。
// 普通のクラス
class Foo { }
// デコレータを使ったクラス
@autotag
class Bar { }
console.log(new Foo().toString()) //=> [object Object]
console.log(new Bar().toString()) //=> [object Bar]