ECMAScript 2015 (ES6) まとめ (クラス編)

0 件のコメント

ECMAScript2015 (ES6) で機能追加されたもののうち、今回は class に関連する部分をピックアップしてまとめていきます。 ついに JavaScript でも クラス が使えるようになった! …のですが、不完全な部分もありますので、この記事を読んでそんなところもピックアップしてもらえればと思います。

ちなみに、ES2015 に関連する まとめ記事 は以下の通りです。

関連記事


目次


JavaScript の クラス 概要

Java や C# 等の言語には最初から class キーワード が存在していますが、 JavaScript には ES2015 まで存在しませんでした。 ES2015 に対応しているブラウザから class が使えるようになります。

JavaScript において class を利用する簡単な例を以下に載せます。

// クラスを宣言
class Car {
  constructor (name) {
    this.name = name;
  }
  
  drive () {
    console.log(`drive ${this.name}.`);
    console.log('zoom zoom ...');
  }
}

// クラスをインスタンス化して利用
var mycar = new Car('ponkotsu');
mycar.drive();

クラスの宣言は class キーワード に続けて クラス名 を指定することでできます。 クラスの内容は オブジェクト 定義する記載方法と似ていますが、 メンバの区切りにカンマ不要な点が異なります。 クラスを利用する際のインスタンス化は new で行い、メソッド呼び出しは . で行うあたりはよくある記法と同じかと思います。

クラス の 定義

クラス宣言

クラス宣言を行うには class キーワード を利用します。 宣言方法は「classキーワード に引き続き クラス名 を記述する方法」と「変数として クラス定義 する方法」の2通りがあります。

構文
class ClassName {
  definitions
}
var ClassName = class [ClassNameAlias] {
  definitions
}
ClassName
クラス名を指定。インスタンス生成時に利用する名前。
ClassNameAlias
クラス内部で利用するクラス名。staticメソッドを呼び出すとき等に使う。オプションなので定義しなくても動作する。
definitions
クラスの内容を記述。

コンストラクタ

その名の通り、クラスをインスタンス化するとき呼ばれる特別なメソッドです。 名称が決まっており constructor を利用します。 メソッドになるため仮引数やメソッド本体の記載方法は通常のメソッドと同じです。 JavaScript の クラス ではメンバ変数の初期化をコンストラクタで行います。

構文
var ClassName = class {
  constructor ([param...]) {
    statements
  }
}
利用例
var Car = class {
  constructor (name) {
    console.log(`create ${name}`);
  }
}

var mycar = new Car('ponkotsu');    // "create ponkotsu"

メソッド

オブジェクトの操作を表すメソッドを定義することができます。 通常の関数と同じで関数名と仮引数を定義します。 利用する際はインスタンス化した後に定義したメソッド名を指定することで呼び出せます。 インスタンス化せずに呼び出せる staticメソッド は static キーワード を用いて定義します。

JavaScript の クラス で通常通りメソッドを追加すると public な扱いになり、どこからでもアクセスできるメソッドになります。 private なメソッドを作りたい場合は ES2015 で追加された Symbol を使うことで疑似的な表現ができると思います。 Symbol はユニークな値のため、その名称を知ったうえで意図的に Symbol を利用してアクセスしない限り メソッド アクセス できません。

構文

publicメソッド

var ClassName = class {
  MethodName ([params...]) {
    statements
  }
}

privateメソッド

var ClassName = class {
  [Symbol('MethodName')] ([params...]) {
    statements
  }
}

staticメソッド

var ClassName = class {
  static MethodName ([params...] {
    statements
  }
}
MethodName
メソッド名
params...
メソッドに渡す仮引数
statements
メソッド本体
利用例

var Car = class {
  constructor(name) {
    this.name = name;
  }

  // publicメソッド
  echo () {
    console.log(this.name);
  }

  // privateメソッド
  [Symbol.for('_echo')]() {
    console.log(`${(new Date(Date.now())).toISOString()} : ${this.name}`);
  }

  // staticメソッド
  static maintenance() {
    console.log('now maintenance...');
  }
};


var o = new Car('hoge');
o.echo();                     // "hoge"
o._echo();                    // TypeError: o._echo is not a function
o['_echo']();                 // TypeError: o._echo is not a function
o[Symbol.for('_echo')]();     // "2016-07-01T00:22:36.471Z : hoge"
Car.maintenance()             // "now maintenance..."

プロパティ

プロパティ(メンバ変数)の定義および初期化は コンストラクタ の中で行います。 プロパティに対するアクセスを setter / getter で制御したい場合は追加で必要な setter / getter を定義を行います。 setter / getter を利用する際は本体となるプロパティは private とするのが通常と思いますので、 Symbol とセットで定義になるかと思います。

構文

通常の定義

var ClassName = class {
  constructor () {
    // publicプロパティ
    this.publicMember = 'prop1';

    // privateプロパティ
    this[Symbol.for('privateMember')] = 'prop2';
  }
}

setter / getter を用いた定義

var ClassName = class {
  constructor () {
    // プロパティの実態
    this[Symbol.for('memberName')] = initialValue;
  }
  
  // getter定義
  get PropertyName () {
    // getterの内容
    return this[Symbol.for('memberName')];
  }

  // setter定義
  set PropertyName (value) {
    // setterの内容
    this[Symbol.for('memberName')] = value;
  }
}
利用例
var Car = class {
  constructor(name) {
    this.name = name;
    this[Symbol.for('created')] = (new Date(Date.now())).toISOString();
    this[Symbol.for('_number')] = Math.floor(Math.random() * 10000);
  }
  getCreatedTime() {
    console.log(this[Symbol.for('created')]);
  }
  echo() {
    console.log(`this name is "${this.name}"`);
  }
  get number() {
    return this[Symbol.for('_number')];
  }
  set number(value) {
    this[Symbol.for('_number')] = value;
  }
};


var o = new Car('hoge');
o.created;                    // undefined
o.getCreatedTime();           // 2016-07-01T01:00:22.833Z  <- インスタンス生成日時
o.echo();                     // this instance's name is "hoge"
o.number;                     // 7184  <- 乱数

継承

あらかじめ作成してあるクラスを継承して新しいクラスを作成することができます。 継承は extends キーワード を利用して親クラスを指定します。

子クラスにおいて親クラスのメソッドを呼ぶ場合、super キーワードを利用して呼び出します。 親クラスのコンストラクタを呼び出す場合は super() で呼び出します。 親クラスのメソッドを呼び出す場合は super.parentMethod() で呼び出します。

子クラスにおいて親クラスのメソッドをオーバーライド(上書き)する場合、同名のメソッドを定義することでオーバーライドできます。

構文
var ChildClassName = class [ChildClassNameAlias] extends ParentClassName {
  definitions
}
ChilClassName
子クラス名
ParentClassName
親クラス名
利用例
// 親クラスの定義
var Car = class {
  constructor(name) {
    this.name = name;
    this.created = (new Date(Date.now())).toISOString();
  }

  getTimeStamp() {
    return this.created;
  }

  drive() {
    console.log('zoom zoom ...');
  }
};

// 子クラスの定義
// Car を継承して Lamborghini を作成
var Lamborghini = class extends Car {
  constructor(name) {
    // 親コンストラクタを呼び出す例
    super(name);
  }

  echo() {
    // 親メソッドを呼び出す
    console.log('call parent class getTimeStamp() : ' + super.getTimeStamp());
  }

  // オーバーライドの例
  drive() {
    console.log(`fire ${this.name} !!`);
  }
};


var car1 = new Lamborghini('lamgorghini');
car1.getTimeStamp();    // "2016-07-01T04:14:01.131Z"
car1.echo();            // call parent class getTimeStamp() : 2016-07-01T04:14:01.131Z
car1.drive();           // fire lamgorghini !!

クラス の 利用

インスタンス化

インスタンス化は new に続いてクラス名を記述することで行えます。 インスタンス化した際は最初に コンストラクタ (constructor メソッド) が呼ばれます。 ちなみに、インスタンス破棄時に呼ばれる デストラクタ は存在しません。

構文
var instance = new ClassName();
利用例
var User = class User {
  constructor () {
    this.id = '';
    this.name = '';
  }
  login () {
    console.log('login');
  }
  logout () {
    console.log('logout');
  }
};

var user = new User();
user.login();
user.logout();

ECMAScript2015 (ES2015 / ES6) から利用できるようになった クラス についてまとめてみました。 JavaScript において クラス を利用するとき利用する setter / getter (ES5) や Symbol型 についてもあわせて記載しました。 この記事一本で JavaScript のクラス作成、利用 は出来る…ハズ!

参考記事