JSでも華麗にOOPをやりたい。華麗にクラス開発がしたい!
prototype実装から始まり、トランスパイラを使って、Haxe、TypeScript、6to5(Babel)等、どこか納得できないまま実装してきた人いませんか?
自分は面倒くさくなって結局prototypeで適当にやっていた始末。
そんな中、久しぶりに「BabelでES6」を書いてみたら、以前諦めていたクラス変数(っぽい)定義方法が実現できたのでそのメモです。
こんな感じでクラス(メンバ)変数の定義がしたかった。
このようにpropAやpropBといった、初期値を持った変数をクラス直下で定義したい。
しかしこれでは残念な事にコンパイルエラーが起きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class MyClass{ propA=0; propB=10; constructor(){ this.init(); } init(){ //メンバ変数を使って足し算する var num=this.propA+this.propB; } } |
ES6ではクラス直下はメソッドしか持てない仕様
http://www.ecma-international.org/ecma-262/6.0/#sec-class-definitions
今までどうやっていたか
constructor()
または、init()
内でプロパティを後から動的に追加する事で、「定義した体」で実現していました。
例におけるinit()
内では、this.propA
やthis.propB
が、constructor()
内で追加されたクラスメンバと認識するまでに脳内コストがかかります。
これがまかり通ってしまうのが、良くも悪くもEcmaScriptって感じです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class MyClass{ constructor(){ this.propA=0; this.propB=10; this.init(); } init(){ //メンバ変数を使って足し算する var num=this.propA+this.propB; } } |
若干の抜け道
実は「初期値を設定しない定義だけ」であればエラーになりません。
先にメンバのみを定義し、init()
内で初期値を設定。
初期値がないので「型」はわかりずらいですが、これであればpropAはクラスの直下にあるのでクラスメンバとして見分けがつきやすいです。
仕様上正しいかは不明ですが、これがやれる限界の方法だと思っていました。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class MyClass{ propA; propB; constructor(){ this.init(); } init(){ this.propA=0; this.propB=10; //メンバ変数を使って足し算する var num=this.propA+this.propB; } } |
あきらめないで。ES6でクラス変数定義
BabelではES7の仕様策定に向けて、クラス変数定義を採用しています。
その設定を有効にする方法でこれをあっさり解決できます。
そのポイントとなるのが「stage-0」という設定です。
手順1:babel-preset-stage-0をインストール
1 |
$ npm install --save-dev babel-preset-stage-0 |
参考:https://babeljs.io/docs/plugins/preset-stage-0/
手順2:stage-0の設定を追記(gulpfile.js)
今回はgulpでやっています。
babelのtransformのpresetsでstage-0を追加します。
1 |
.transform(babelify, {presets: ['es2015','stage-0']}) |
無事にコンパイルできました!やったね!\(^o^)/
個人的にはより従来のプログラムっぽくなり、
ナチュラルにJSが書けるようになったので嬉しい限りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class MyClass{ propA=0; propB=10; constructor(){ this.init(); } init(){ //メンバ変数を使って足し算する var num=this.propA+this.propB; } } |