Deep Insider の Tutor コーナー
>>  Deep Insider は本サイトからスピンオフした姉妹サイトです。よろしく! 
書籍転載:JavaScriptライブラリ実践活用[厳選111]

書籍転載:JavaScriptライブラリ実践活用[厳選111]

オブジェクト指向でコードを記述する[CoffeeScript]

2013年6月20日

書籍転載の14本目(書籍内の番号は「63」)。CoffeeScriptを使用すると、クラスベースのオブジェクト指向で記述できる。その内容を説明する。

WINGSプロジェクト 安西 剛
  • このエントリーをはてなブックマークに追加

書籍転載について

 本コーナーは、技術評論社発行の書籍『JavaScriptライブラリ実践活用[厳選111]』の中から、特にBuild Insiderの読者に有用だと考えられる項目を編集部が選び、同社の許可を得て転載したものです。

 『JavaScriptライブラリ実践活用[厳選111]』の詳細や購入は技術評論社のサイト目次ページをご覧ください。

ご注意

本記事は、書籍の内容を改変することなく、そのまま転載したものです。このため用字用語の統一ルールなどはBuild Insiderのそれとは一致しません。あらかじめご了承ください。

JavaScriptは、初心者でも始めやすい言語ですが、深く理解しバグの少ないコードを書くには言語仕様上の「罠」が潜んでいます。その一例にオブジェクト指向への対応があります。JavaScriptはプロトタイプベースのオブジェクト指向であり、クラスベースのオブジェクト指向ではありません。そこでCoffeeScriptを使用すると、クラスベースのオブジェクト指向で記述できます。

 ここでは、関数とオブジェクト指向について説明します。

関数

 関数は、JavaScriptよりも幅広い表現力を持っています(リスト063-01)。

CoffeeScript
# 1関数の宣言
square = (x) -> x * x
# 引数が存在する関数
sum = (n, m) -> n + m
# 2引数にデフォルト値がある
minus = (n = 2, m = 4) -> n - m
# 3複数行の関数
multi = (n) ->
  if n < 2
    square(n, 5)
  else
   sum(n, 2)
# 4可変長の引数
sum = (nums...) ->
  result = 0
  result += num for num in nums ―――5
  result
リスト063-01 syntax_function.coffee

 1関数は「->」で定義します。1行にも複数行にも記述することができます。また、returnを省略することができ、自動的に最後の構文に自動的にreturnが付きます。
 2引数にデフォルト値を指定できます。コンパイル後のコード(リスト063-02)を見ると、if文でnullだった場合にデフォルト値を格納します。変換後のコードを見ると、その意図がわかりやすいと思います。
 3複数行での関数も定義できます。この場合も最後の処理は自動的にreturnが付きます。
 4可変長の引数を...で定義できます。
 5配列を回して格納していくことも可能です(for~in命令については後述)。コンパイル後のJavaScriptを見てみると、__slice.call(arguments, 0)で明示的に配列に引数を入れています。JavaScriptで記述すると、ここまで複雑な構文になりますが、CoffeeScriptで記述すると少ない行数で記述できるようになります。

JavaScript
(function() {
  var minus, multi, square, sum,
    __slice = [].slice;
  square = function(x) { ――――――1
    return x * x;
  };
  sum = function(n, m) {
    return n + m;
  };
  minus = function(n, m) { ―――――2
    if (n == null) {
      n = 2;
    }
    if (m == null) {
      m = 4;
    }
    return n - m;
  };
  multi = function(n) { ――――――3
    if (n < 2) {
      return square(n, 5);
    } else {
      return sum(n, 2);
    }
  };
  sum = function() { ――――――4
    var num, nums, result, _i, _len;
    nums = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
    result = 0;
    for (_i = 0, _len = nums.length; _i < _len; _i++) {
      num = nums[_i];
      result += num;
    }
    return result;
  };
}).call(this);
リスト063-02 syntax_function.js

クラス型オブジェクト指向

 JavaScriptはクラス型オブジェクト指向ではなく、プロトタイプベースのオブジェクト指向となっており、処理の考え方が違います。Javaなどの他の言語と同様のオブジェクト指向の感覚で使用すると、想定どおりに動作しないことがあります。

 そこで、CoffeeScriptでは、クラス型オブジェクト指向をサポートしています。これだけでも、CoffeeScriptを利用する価値があるでしょう。

 ではリスト063-03を例に、CoffeeScriptでのクラス型オブジェクト指向の書き方をを見ていきましょう。

CoffeeScript
###
  クラス型オブジェクト指向
### # 1クラス宣言
class Member
  # 変数の宣言
  yasunishi: 'Hello' # publicなインスタンス変数
  @yamada: 'Hello'   # publicなstatic変数
  takano = 'Hello'   # privateなstatic変数

  # 2コンストラクタ(@を付けることで引数をインスタンス変数に格納)
  constructor: (@yasunishi) ->

  # 3メンバ関数
  func: ->
    @yasunishi    # publicなインスタンス変数へアクセス
    Member.yamada # publicなstatic変数へアクセス
    takano        # privateなstatic変数へアクセス

  # 4staticなメンバ関数
  @staticfunc: ->
    # staticな関数からstaticなプロパティへは@でアクセスできる
    @yamada

# 5継承
class SubClass extends Member
  func: ->
    # スーパークラスの同名のメソッドを呼び出す
    super()
リスト063-03 oo.coffee

1クラス宣言

 class命令で行います。変数の宣言は宣言の方法によって扱いが違います。

  • 変数名:内容(publicなインスタンス変数)
  • @変数名:内容(publicなstatic変数)
  • 変数名=内容(privateなstatic変数)

2コンストラクタ

 引数に@とインスタンス変数名が付いていますが、これは次のようなインスタンス変数に引数を格納するコードの省略形です。

constructor: (arg) ->
  @yasunishi = arg

3関数宣言

 メンバ変数へのアクセス方法です。@は、メンバ関数内だとthisと同じ意味となり、このサンプルの場合、this.yasunishiとなります。publicなstatic変数はクラス名.変数名となり、privateなstatic変数は変数名のみでアクセスします。

4staticな関数

 @を付けることにより、staticな関数になります。staticな関数からstaticなプロパティへは@でアクセスできます。

5継承

 extends命令でスーパークラスを指定します。また、関数内ではsuperメソッドで同名のスーパークラスのメソッドを呼び出します。

 コンパイルを行うとリスト063-04のように変換されます。

JavaScript
(function() {
  var Member, SubClass,
    __hasProp = {}.hasOwnProperty,
    __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; };
  Member = (function() {
    var takano;
    Member.prototype.yasunishi = 'Hello';
    Member.yamada = 'Hello';
    takano = 'Hello';
    function Member(yasunishi) {
      this.yasunishi = yasunishi;
    }
    Member.prototype.func = function() {
      this.yasunishi;
      Member.yamada;
      return takano;
    };
    Member.staticfunc = function() {
      return this.yamada;
    };
    return Member;
  })();

  SubClass = (function(_super) {
    __extends(SubClass, _super);
    function SubClass() {
      return SubClass.__super__.constructor.apply(this, arguments);
    }
    SubClass.prototype.func = function() {
      return SubClass.__super__.func.call(this);
    };
    return SubClass;
  })(Member);
}).call(this);
リスト063-04 oo.js

※以下では、本稿の前後を合わせて5回分(第12回~第16回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

書籍転載:JavaScriptライブラリ実践活用[厳選111]
12. JasmineのSpy機能でテストダブルを作成する

書籍転載の12本目(書籍内の番号は「109」)。Jasmineでテスト対象オブジェクトが持つメソッドの戻り値を固定値に変更したり、そのメソッドが実行されたかどうかを検証したりするために、Spy機能を使用する方法を解説。

書籍転載:JavaScriptライブラリ実践活用[厳選111]
13. 短くかつ安全で高性能なコードを書く[CoffeeScript]

書籍転載の13本目(書籍内の番号は「62」)。短い記述で、安全かつ高性能なJavaScriptコードを生成できる「CoffeeScript」の基本的な使い方を説明する。

書籍転載:JavaScriptライブラリ実践活用[厳選111]
14. 【現在、表示中】≫ オブジェクト指向でコードを記述する[CoffeeScript]

書籍転載の14本目(書籍内の番号は「63」)。CoffeeScriptを使用すると、クラスベースのオブジェクト指向で記述できる。その内容を説明する。

書籍転載:JavaScriptライブラリ実践活用[厳選111]
15. 処理を短く記述する[CoffeeScript]

書籍転載の15本目(書籍内の番号は「64」)。CoffeeScriptの基本構文のうち、数値や文字列表現、配列、for~in、unless/untilの記述方法を説明する。

書籍転載:JavaScriptライブラリ実践活用[厳選111]
16. JavaScriptでクッキーを簡単に操作する[jquery.cookie]

書籍転載の16本目(書籍内の番号は「61」)。JavaScriptでのクッキー操作をごくシンプルなコードで実装できる「jquery.cookieプラグイン」の基本的な使い方を説明する。

サイトからのお知らせ

Twitterでつぶやこう!