- 更新日: 2015年2月10日
- jQuery & JavaScript
CoffeeScript入門、クラス継承とメソッドのオーバーライド
JavaScript でもプログラムがある程度の規模以上になると、クラスの継承やメソッドのオーバーライドなどを使いたくなります。しかし、素の JavaScript でのオブジェクト指向なプログラミングは、片手間で JavaScript を書く私には結構辛い。prototype ベースのオブジェクト指向プログラミングは、クラスベースのものに比べて難しいと感じます。
ということで、これまで見よう見まねだけで書いてた CoffeeScript を、ちょっと腰を据えて小1時間ほど勉強してみました。CoffeeScript であれば、class ベースのオブジェクト指向なプログラムをすっきり書けます。Ruby/Python/JavaScript が分かる人であれば、それほど学習コストも高くないと思います。
クラスの継承やメソッドのオーバーライドなど、よく使いそうな機能の書き方の定石を知りたかったため、以下のページ等に目を通しました。
The Little Book on CoffeeScript – Classes
すぐに分かる CoffeeScript によるクラスの書き方 | Developers.IO
CoffeescriptのClassの作り方メモ – Qiita
CoffeeScript でクラスベースのオブジェクト指向プログラミングをするための基礎知識 – わからん
そのほか CoffeeScript の基本文法については、以下ページを参考。The Little Book on CoffeeScript の解説は素晴らしく分かりやすいです。あと入門であれば、定番のドットインストール。
The Little Book on CoffeeScript
CoffeeScript入門 (全13回) – プログラミングならドットインストール
書いてみた CoffeeScript でのクラス継承
学習のために、以下の CoffeeScript でのクラス継承とメソッドをオーバーライドするコードを書いてみました。Shape クラス(スーパークラス/親クラス)を、Rectangle(長方形)、Triangle(三角形)、Circle(円)のサブクラス(子クラス)が継承する例です。面積を求める area メソッドを、各々サブクラスでオーバーライドしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
### Learning CoffeeScript Super Class: Shape Sub Class : Rectangle, Triangle, Circle ### class Shape # class variable, @ is equal to this @message: "I am Shape Class" # class method, fat allow fixes this(@) @alert_message: => alert @message # can use default values for method arguments constructor: (x = 0, y = 0) -> # instance variables @x = x @y = y # public instance method area: -> "Can not calculate my area!" class Rectangle extends Shape constructor: (x, y) -> super(x, y) area: -> @x * @y class Triangle extends Shape constructor: (x, y) -> super(x, y) area: -> @x * @y / 2 class Circle extends Shape constructor: (r) -> super(r) area: -> Math.PI * @x * @x # Shape sha = new Shape alert sha.area() # => Can not calculate my area! Shape.alert_message() # => I am Shape Class # sha.alert_message() # => TypeError: sha.alert_message is not a function # Rectangle rec = new Rectangle(3, 5) alert rec.area() # => 15 Rectangle.alert_message() # => I am Shape Class # Triangle tri = new Triangle(3, 5) alert tri.area() # => 7.5 # Circle cir = new Circle(3) alert cir.area() # => 28.274333882308138 |
CoffeeScript だと、クラスの継承を extends を使ってすっきり書けました。メソッドのオーバーライドもちゃんと機能していますし、クラスメソッドとインスタンスメソッドの違い、クラス変数とインスタンス変数の違いもはっきりします。
素の JavaScript にコンパイル後のコード
CoffeeScript のコードは、CoffeeScript の TRY COFFEESCRIPT タブでコンパイルでき、コンパイル後の JavaScript コードと実行結果を確認できます。
上記クラス継承の CoffeeScript コードからコンパイルされた実際の JavaScript コードは以下です。ややこしいですけど、読めば何となく分かります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
/* Learning CoffeeScript Super Class: Shape Sub Class : Rectangle, Triangle, Circle */ var Circle, Rectangle, Shape, Triangle, cir, rec, sha, tri, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, __hasProp = {}.hasOwnProperty; Shape = (function() { Shape.message = "I am Shape Class"; Shape.alert_message = function() { return alert(Shape.message); }; function Shape(x, y) { if (x == null) { x = 0; } if (y == null) { y = 0; } this.x = x; this.y = y; } Shape.prototype.area = function() { return "Can not calculate my area!"; }; return Shape; })(); Rectangle = (function(_super) { __extends(Rectangle, _super); function Rectangle(x, y) { Rectangle.__super__.constructor.call(this, x, y); } Rectangle.prototype.area = function() { return this.x * this.y; }; return Rectangle; })(Shape); Triangle = (function(_super) { __extends(Triangle, _super); function Triangle(x, y) { Triangle.__super__.constructor.call(this, x, y); } Triangle.prototype.area = function() { return this.x * this.y / 2; }; return Triangle; })(Shape); Circle = (function(_super) { __extends(Circle, _super); function Circle(r) { Circle.__super__.constructor.call(this, r); } Circle.prototype.area = function() { return Math.PI * this.x * this.x; }; return Circle; })(Shape); sha = new Shape; alert(sha.area()); Shape.alert_message(); rec = new Rectangle(3, 5); alert(rec.area()); Rectangle.alert_message(); tri = new Triangle(3, 5); alert(tri.area()); cir = new Circle(3); alert(cir.area()); |
コンパイル後の JavaScript コード解読
__extends による継承
・継承は、__extends メソッドを定義してそれを利用して実現。
・__extends メソッドは、親クラスのプロパティを子クラスにコピーする。
・ctor() がちょっとよく分かりませんが、ctor.prototype に親クラスの prototype(parent.prototype) を設定して、child.prototype に new ctor() を割り当てている。
・最後に child の __super__ に parent.prototype を割り当てて、__extends メソッドは child(子クラス)を return。
クラスメソッド
1 2 3 |
class Shape @message: "I am Shape Class" # ... |
のように、class 定義の文脈で @ (this) を使ったプロパティ定義は…
1 |
Shape.message = "I am Shape Class"; |
のようにクラスのプロパティに変換されています。
constructor(コンストラクタ)
constructor は、
1 |
function Shape(x, y) { ... } |
に変換。
public なインスタンスメソッド
class で @ なしで定義したメソッドは、インスタンスメソッドとなる。area は、
1 |
Shape.prototype.area = function() { ... } |
に変換されています。
その他 private メソッドの定義やクラスでファイルを分ける時など
private メソッドやファイルを分ける方法は、以下の記事が参考になりました。
すぐに分かる CoffeeScript によるクラスの書き方 | Developers.IO
private メソッドの定義は、class 内のローカルなメソッドとして定義して、呼び出しには call を使う。
1 2 3 4 5 6 |
class Hoge private_func = (arg) -> # do something public_func: (arg) -> private_func.call @, arg |
CoffeeScript でクラスをファイル毎に分割する場合は、グローバル変数にクラス名を設定しないと、他のファイルから参照できません。なので、window オブジェクトを使います。window オブジェクトのプロパティとしてクラスを定義することで、他のファイルから参照可能になるそうです。
1 |
class window.ClassName |
なるほどなー。
とりあえず CoffeeScript を使うと、オブジェクト指向なプログラムをすっきり書けることが分かって良かったです。ちょっと食わず嫌いで見よう見まねだけで使っていたのですが、今後は CoffeeScript を積極的に使っていこうと思います。間違っている箇所がありましたら、つっこみお願いいたします!
- jQuery & JavaScript の関連記事
- React.js用にESLintをインストールして設定、JavaScriptコードを楽に検証しよう
- JavaScriptでHTMLコメント要素を取得する
- YahooのJavaScriptマップAPI(YOLP)で地図を描画
- HTML5のGeolocation APIで現在地の位置情報(緯度/経度)を取得するJavaScriptコード
- JavaScriptでキャメルケースを単語に分割
- Browserify + GulpでクライアントのJavaScript / CoffeeScriptでrequire
- JavaScript/jQueryでDOM要素が存在するか確認する方法
- JavaScriptでスクロールを一時的に止める
- JavaScriptでcapitalize、アルファベット一文字目を大文字にする
- JavaScriptでrangeオブジェクトから座標を取得するコード
Leave Your Message!