クラスいらないと思う
- カテゴリ:
- JavaScript
- コメント数:
- Comments: 2
◆ this が面倒
◆ 関数にメソッドを渡すときは特に
◆ クラスを使うメリットがない
◆ bind したりプロパティに代入するなら prototype だけに関数を置いて効率化できない
◆ プロパティ代入だと継承して親メソッド呼び出せないし そもそも継承を使わない
◆ 関数のみで良いと思う
◆ 関数にメソッドを渡すときは特に
◆ クラスを使うメリットがない
◆ bind したりプロパティに代入するなら prototype だけに関数を置いて効率化できない
◆ プロパティ代入だと継承して親メソッド呼び出せないし そもそも継承を使わない
◆ 関数のみで良いと思う
React を書いてると this を一切見なくて済みますし this が出てこなければ余計なところに気を使わなくていいですし この点ではすごく快適です
その分 他のツールを使っているときに クラスが出てきて this が入ってくるとすごくイヤな気分になります
クラス構文でも prototype でも クラス風にすると this が入ってきて関数に渡すときに不便です
単純に関数に渡した場合に this のコンテキストが変わるので
これを避けるためには
のように bind するとか コンテキストを維持して呼び出す関数を作って渡すとか
一手間必要です
クラス構文でメソッド定義ではなく プロパティ代入とすれば回避はできます
全部これでいいやと思うほどですが これってクラスのメリットがなくなってるんですよね
prototype にメソッドが定義されずすべてのオブジェクトのプロパティに関数を代入しています
メソッドなら関数の実体はひとつにしてそれぞれのオブジェクトが関数を持たなくて良いメリットがあるのですが それがなくなります
しかしメソッド定義にしても関数を渡すときに bind したりその場で関数を作るなら結局関数をオブジェクトごとに作ってるのと変わりません
メソッドを関数に渡す前提だと メソッド定義か代入かに関わらずこのクラスのメリットは活かせなさそうです
これまではインスタンスを大量に作るなら効率的にクラスの方がいいかなと使い分ける基準にしていたこともありましたが この点ではクラスにする意味がなくなりました
他のクラスのメリットには継承ができることがあります
これは prototype に関数が入ってる前提なので プロパティ代入になると動かなくなります
B.prototype.method はないので super.method() 呼び出しに失敗します
prototype にも関数があればいいので こういうことをすれば一応動かせます
動くとはいえ 見た目と二度手間感からこれは避けたいところです
それに そもそも継承っているのでしょうか?
普段から継承が必要になること自体がほぼないです
CustomElements 以外で extends を書いた記憶なんてほぼないです
必要になっても 継承以外の方法も取れます
これでいいと思うんです
内部で親クラスのインスタンスを持っていると メモリ使用量や関数を 1 つ多く呼び出す分パフォーマンスは落ちますが 今の時代に気にするほどのものではないはずです
React でも継承ではなく合成を使うべき みたいなこと言ってますし
これら以外にクラスを使うメリットって特に思いつかないですし それらが活かせないなら関数で十分だと思います
シンプルな関数なので クラスよりも読みやすいですし this がいらないです
value が外から見れないので 公開したくないものを簡単に隠せます
公開したいなら返すオブジェクトに含めて アクセスはそのオブジェクトを経由すればいいです
というわけで 最近はクラスはほとんど書いてないです
特に困ってませんが instanceof が使えないなと思ったことはあります
ただそれも返すオブジェクトに $type みたいなプロパティを用意して型情報を入れておけば済みます
扱いづらい instanceof 演算子を使わず単なる === 比較でできます
また 継承はしてないけどその型だと扱わせたいときがたまにあります
そういうときにこの方法だとプロパティに入ってる型名の書き換えで対応できます
プロパティに含めたくないなら 特別に扱えるように Symbol をキーにしたり WeakSet にインスタンスオブジェクトを入れることでも対応できます
クラスを積極的に使ってる人って TypeScript で書いてる人だったりしますし JavaScript だと関数だけでも良さそうです
その分 他のツールを使っているときに クラスが出てきて this が入ってくるとすごくイヤな気分になります
クラス構文でも prototype でも クラス風にすると this が入ってきて関数に渡すときに不便です
class A {
value = 10
method() {
console.log("value is", this.value)
}
}
const a = new A()
a.method()
// value is 10
単純に関数に渡した場合に this のコンテキストが変わるので
setTimeout(a.method, 0)
// value is undefined
これを避けるためには
setTimeout(a.method.bind(a), 0)
setTimeout(() => a.method(), 0)
のように bind するとか コンテキストを維持して呼び出す関数を作って渡すとか
一手間必要です
クラス構文でメソッド定義ではなく プロパティ代入とすれば回避はできます
class B {
value = 10
method = () => {
console.log("value is", this.value)
}
}
const b = new B()
b.method()
// value is 10
setTimeout(b.method, 0)
// value is 10
全部これでいいやと思うほどですが これってクラスのメリットがなくなってるんですよね
prototype にメソッドが定義されずすべてのオブジェクトのプロパティに関数を代入しています
メソッドなら関数の実体はひとつにしてそれぞれのオブジェクトが関数を持たなくて良いメリットがあるのですが それがなくなります
しかしメソッド定義にしても関数を渡すときに bind したりその場で関数を作るなら結局関数をオブジェクトごとに作ってるのと変わりません
メソッドを関数に渡す前提だと メソッド定義か代入かに関わらずこのクラスのメリットは活かせなさそうです
これまではインスタンスを大量に作るなら効率的にクラスの方がいいかなと使い分ける基準にしていたこともありましたが この点ではクラスにする意味がなくなりました
他のクラスのメリットには継承ができることがあります
これは prototype に関数が入ってる前提なので プロパティ代入になると動かなくなります
class C extends B {
method = () => {
super.method()
console.log("C.method")
}
}
const c = new C()
c.method()
// TypeError: (intermediate value).method is not a function
B.prototype.method はないので super.method() 呼び出しに失敗します
prototype にも関数があればいいので こういうことをすれば一応動かせます
class D {
value = 10
method() {
console.log("value is", this.value)
}
method = this.method.bind(this)
}
class E extends D {
method() {
super.method()
console.log("E.method")
}
method = this.method.bind(this)
}
new D().method()
// value is 10
new E().method()
// value is 10
// E.method
動くとはいえ 見た目と二度手間感からこれは避けたいところです
それに そもそも継承っているのでしょうか?
普段から継承が必要になること自体がほぼないです
CustomElements 以外で extends を書いた記憶なんてほぼないです
必要になっても 継承以外の方法も取れます
class F {
value = 10
method = () => {
console.log("value is", this.value)
}
}
class G {
sup = new F()
method = () => {
this.sup.method()
console.log("G.method")
}
}
new G().method()
// value is 10
// G.method
これでいいと思うんです
内部で親クラスのインスタンスを持っていると メモリ使用量や関数を 1 つ多く呼び出す分パフォーマンスは落ちますが 今の時代に気にするほどのものではないはずです
React でも継承ではなく合成を使うべき みたいなこと言ってますし
これら以外にクラスを使うメリットって特に思いつかないですし それらが活かせないなら関数で十分だと思います
const f1 = () => {
const value = 10
const method = () => {
console.log("value is", value)
}
return { method }
}
シンプルな関数なので クラスよりも読みやすいですし this がいらないです
value が外から見れないので 公開したくないものを簡単に隠せます
公開したいなら返すオブジェクトに含めて アクセスはそのオブジェクトを経由すればいいです
const f2 = () => {
const method = () => {
console.log("value is", exposed.value)
}
const exposed = {
method,
value: 10,
}
return exposed
}
というわけで 最近はクラスはほとんど書いてないです
特に困ってませんが instanceof が使えないなと思ったことはあります
ただそれも返すオブジェクトに $type みたいなプロパティを用意して型情報を入れておけば済みます
扱いづらい instanceof 演算子を使わず単なる === 比較でできます
また 継承はしてないけどその型だと扱わせたいときがたまにあります
そういうときにこの方法だとプロパティに入ってる型名の書き換えで対応できます
プロパティに含めたくないなら 特別に扱えるように Symbol をキーにしたり WeakSet にインスタンスオブジェクトを入れることでも対応できます
const f3 = () => {
const instance = {}
f3.instances.add(instance)
return instance
}
f3.instances = new WeakSet()
const obj = f3()
f3.instances.has(obj)
// true
クラスを積極的に使ってる人って TypeScript で書いてる人だったりしますし JavaScript だと関数だけでも良さそうです