最新JavaScript 「ECMAScript2015」を誰にもバレずに、こっそりさわってみる

最近癒しを求めて、こそこそJavaScriptを書いている クリエイターのSAWAMICHIOです。 実はJavaScriptは2015年6月に「ECMAScript2015」「通称ES6?」と呼ばれる新仕様が発表され、 大きな進化を遂げでいるのを今更ながらピックアップしてみました。 JS以外のプログラミング言語を深く知るわけではないのでなんとも言えないのですが、 新仕様で特に注目を集めてそうなのがclass構文の追加です。 それまではプロトタイプという非常にわかりにくい苦行のような書き方だったのですが、 ES6ではよりポピュラーな記法でクラスを定義できるようになったようです。

従来のプロトタイプベースでのクラス(コンストラクタ)の定義

function Person( name, gender ) {
  this._name = name
  this._gender = gender
}

Person.prototype.string = function() {
  return this._name + 'は' + this._gender + 'です。'
}

var sawa = new Person( 'SAWAMICHIO', '男' )
console.log( sawa.string() )
↑よくある例です。はい。 関数を作ってそれをnew演算子を介して呼び出すと急にコンストラクタとして動作し、 インスタンス化したオブジェクトから親クラスのメソッドにアクセスできるというやつです。 ↓同じことをこのように書き換えることができます。

最新のクラス構文でのコンストラクタの定義

class Person {
  constructor( name, gender ) {
    this._name = name
    this._gender = gender
  }

  string() {
    return this._name + 'は' + this._gender + 'です。'
  }
}

const sawa = new Person( 'SAWAMICHIO', '男' )
console.log( sawa.string() )
「class クラス名」でクラスを定義する書き方は、 JavaやC言語ではおなじみらしいのですがワタシは知りません。 クラスからオブジェクトを生成するコンストラクタは、そのものズバリ 「constructor」で定義するようです。 コンストラクタの定義は省略することもでき、 省略した場合は、「constructor(){}」という空のコンストラクタが 暗黙のうちに定義されます。 クラスを定義したら、new演算子でクラスからオブジェクトを生成できます。 この辺は一緒ですね。 またクラスの定義は下記のようにクラスリテラルで記述して、 変数に代入する書き方もできます。

クラスリテラルを使ってコンストラクタを定義する

const Person = class {
  constructor( name, gender ) {
    this._name = name
    this._gender = gender
  }

  string() {
    return this._name + 'は' + this._gender + 'です。'
  }
}

static修飾子で静的メソッドを定義できる

上記までのものは、単に書き方が変わっただけっぽかったのですが、 クラス構文には静的メソッドを持たせることができます。 この場合、オブジェクトをわざわざインスタンス化することなく、 「クラス名.静的メソッド」で実行できます。
class Calc {
  static sum( num1, num2 ) {
    return num1 + num2
  }
}

console.log( Calc.sum( 5, 5 ) )
[実行結果] 10

setter/getterを使ったプロパティの定義

ここではsetter/getterを使って Personクラスにageプロパティを追加しています。
class Person {
  set age( value ) {
    console.log( 'setter呼び出し' )
    if ( value < 0 ) {
      throw new RangeError( 'ageは正数で' )
    }
    this._age = value
  }

  get age() {
    console.log( 'getter呼び出し' )
    return this._age
  }
}

const kawaguchi = new Person()

kawaguchi.age = 22
console.log( kawaguchi.age )

kawaguchi.age = -22
console.log( kawaguchi.age )
[実行結果] setter呼び出し getter呼び出し 22 setter呼び出し x RangeError: ageは正数で
setのコードブロックがsetterで、ageプロパティに値を設定した時に自動的に実行されます。 同じくgetのコードブロックがgetterで、ageプロパティから値を取得しようとした時に自動的に実行されます。

setterを省略して読み取り専用のプロパティを定義する

class Person {
  get age() {
    console.log( 'getter呼び出し' )
    return this._age = 22
  }
}

const kawaguchi = new Person()
console.log( kawaguchi.age )

kawaguchi.age = 92
console.log( kawaguchi.age )

getterを省略して書き込み専用のプロパティを定義する

class Person {
  set age( value ) {
    console.log( 'setter呼び出し' )
    if ( value < 0 ) {
      throw new RangeError( 'ageは正数で' )
    }
    this._age
  }
}

var kawaguchi = new Person()
kawaguchi.age = 22
console.log( kawaguchi.age )

extends構文を使ったクラスの継承

class Person {
  constructor( name, gender ) {
    this._name = name
    this._gender = gender
  }

  string() {
    return this._name + 'は' + this._gender + 'です。'
  }
}

class FrontierVision extends Person {
  constructor( name, gender, job ) {
    super( name, gender )
    this._job = job
  }

  string() {
    return this._name + 'は' + this._job + 'です。'
  }
}

const kawaguchi = new FrontierVision( '川口', '男', 'エンジニア' )
console.log( kawaguchi.string() )
クラスの重要な機能の一つにオブジェクトどうしの継承関係を築けるというのがあります。 JS自体、Objectを頂点とした壮大な宇宙を構成しているように あるクラス(親クラス)から、そのクラスのメソッドやプロパティを引き継いだ(子クラス)を定義できる機能です。 従来はプロトタイプ継承というJS特有の?やり方で実現していましたが、新しい構文では「extends」という構文で継承を実現できるようになり よりシンプルにわかりやすく表現することができます。 新しいclass構文によってガラリと変わった印象を持ちますが、内部的にはやはり従来通りのプロトタイプベースのようです。 その証拠にclass構文で定義した Personをtypeof演算子で確認すると function(関数)と表示されます。 さらに「Person.prototype.プロパティ = 関数リテラル」という従来の記法でメソッドを追加することも可能です。 表面的にはガラリと変わって新しい言語かのようになりましたが、実態は 今までのJavaScriptそのものということで安心できますね。 いちいち学習し直さないでいいですから。 他にも気になる機能がたくさん追加された「ECMAScript2015」ですが、それはまた次の機会に 御免。