LoginSignup
2
3

More than 5 years have passed since last update.

ES2015 で Python の @classmethod のように static なメソッド内で自クラスを参照するには this を使えば良い?

Last updated at Posted at 2016-06-12

Python なら、クラスメソッド内から自分のクラスを第一引数で参照することができる。
クラスメソッドを通じて自分自身のインスタンスを提供する手段はプログラミングではよくある。
たとえば datetime.date.today()datetime.date のインスタンスを生成する。
date(year, month, day) と初期化する作業を、肩代わりしてクラスメソッドが行って返却している。

Python ではデフォルトで第一引数が呼び出し元になっており、
メソッドでは self 、クラスメソッドでは cls という変数名をつける慣習になっている。

ES2015 には static という Python の @staticmethod デコレータに相当するキーワードは存在するが、 @classmethod に相当するキーワードがない。
ではどうやるか という話。 (自分でもこのやり方で合っているか自信がない)

試した環境は NodeJS v6.1.0 。既に V8 でサポートされているので特に babel を経由していない。

まず Python のコード例を書く。

Python での例

class X(object):

    @classmethod
    def create(cls):
        return cls()


class Y(X):
    pass


x = X.create()
y = Y.create()

print(isinstance(x, X))
print(isinstance(y, X))
print(isinstance(y, Y))
実行結果
True
True
True

JavaScript (ES2015) での失敗例

class X {
  static create() {
    return new X();
  }
}

class Y extends X {};

const x = X.create();
const y = Y.create();

console.log(x instanceof X);
console.log(y instanceof X);
console.log(y instanceof Y);
実行結果
true
true
false

X 内で new X(); がハードコードされてしまっているため、
継承した Ycreate() により生成されるインスタンスである y までもが、
実際には Y ではなく単なる X になってしまっている。

これは全く望み通りではない。

JavaScript (ES2015) での成功例 (冗長 ver)

冗長だがシンプルに、新しく static メソッドを再定義する戦略をやってみる。

class X {
  static create() {
    return new this();
  }
}

class Y extends X {
  static create() {
    return new Y();
  }
}

const x = X.create();
const y = Y.create();

console.log(x instanceof X);
console.log(y instanceof X);
console.log(y instanceof Y);
実行結果
true
true
true

ちゃんと望み通りの結果になっている。
yY のインスタンスであるし、YX を継承している。
しかし、これでは継承するたびに全てのクラスメソッドを再定義する必要がある。
そのために、元のクラスでの定義を常に把握しておかなくてはならなくなってしまう。
不便だ。

JavaScript (ES2015) での成功例

そこで、いろいろやっているうちに this を思い出した。
Python での selfthis に相当するなら、同じ関係がクラスメソッドでも成り立つのではないか?
なるほど、クラスから生えている static なメソッドをドット演算子で呼んだら、 this はそのクラスになる……。

というわけでやってみた。

class X {
  static create() {
    return new this();
  }
}

class Y extends X {};

const x = X.create();
const y = Y.create();

console.log(x instanceof X);
console.log(y instanceof X);
console.log(y instanceof Y);
実行結果
true
true
true

目論見通り。
yY のインスタンスであるし、YX を継承している。
ハードコードされていないので Ycreate() を再定義する必要がない。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3