Smart Communication Design Company
ホーム > ナレッジ > Blog > Apps Blog > 2015年11月 > ES2015による継承の方法

ES2015による継承の方法


インタラクションアーキテクト 大室

2015年6月17日、最新のJavaScriptの標準仕様となるECMA-262 6th Edition (ECMAScript 6, ES6, ECMAScript 2015, ES2015など複数の呼称がありますが、本記事では以降ES2015と略します) が正式に承認されました。
ES2015は、クラスやModules、Generatorや非同期処理のPromise、taple、Allow関数など、他にもたくさんの開発者にとって嬉しい新機能が加わりました。

今回は個人的に一番待ち望んでいたクラスを使って、オブジェクト指向プログラミングの基礎である継承の方法について、ES3/ES5/ES2015といった各バージョンごと説明したいと思います。

なお、JavaScriptは柔軟な書き方ができるのがひとつの特徴であるため、ここにあげた例が唯一無二の正解というわけではなく、あくまでひとつの例と考えてください。
また、ES3/ES5にクラスはありませんが本記事では説明の都合上、「クラスに相当するオブジェクト」のことを「クラス」と表現しています。

ES3

// ES3は、Object.create が使えないため、代理クラスを使用する
function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
}
// スーパークラス
function Animal(bay) {
    this.bay = bay;
}
Animal.prototype.greet = function() {
    return this.bay;
};
// サブクラス
function Dog(name) {
    Animal.call( this, name );
}
// サブクラスにスーパークラスを継承させる
Dog.prototype = object( Animal.prototype );
Dog.prototype.constructor = Dog;
// サブクラスのメソッドを新たに定義
Dog.prototype.superGreet = function() {
    return this.bay + '!!!';
};
// クラスをインスタンス化
var dog = new Dog('bow wow');
console.log( dog.greet() );
console.log( dog.superGreet() );

まずはES3に対応した一例です。
特徴は以下の部分です。

Dog.prototype = object( Animal.prototype );

事前に定義したobject関数を使って、サブクラスのprototypeに追加しています。
ここで、

Dog.prototype = new Animal();

とすると、newした段階でコンストラクタが呼ばれてしまい、さらにサブクラスをnewする段階でももう一度コンストラクタが呼ばれてしまいます。
これは無駄なコストですし、バグの温床にもなります。なによりコンストラクタとして期待する挙動と異なります。
そのため、上記のような方法をとっています。

ES5

// スーパークラス
function Animal(bay) {
    this.bay = bay;
}
Animal.prototype.greet = function() {
    return this.bay;
};
// サブクラス
function Dog(name) {
    Animal.call( this, name );
}
// サブクラスにスーパークラスを継承させる
Dog.prototype = Object.create( Animal.prototype );
Dog.prototype.constructor = Dog;
// サブクラスのメソッドを新たに定義
Dog.prototype.superGreet = function() {
    return this.bay + '!!!';
};
// クラスをインスタンス化
var dog = new Dog('bow wow');
console.log( dog.greet() );
console.log( dog.superGreet() );

ES5になると、Object.create()が使えるため、少しスッキリします。

このようにES5までは、prototypeチェーンに継承させたいprototypeオブジェクトを追加することで、(個人的な意見ですが、やや強引な方法で)継承を実現していました。

ES2015

// スーパークラス
class Animal {
    constructor(bay) {
        this.bay = bay;
    }
    greet() {
        return this.bay;
    }
}
// サブクラス
// extends キーワードで継承
class Dog extends Animal {
    constructor(bay) {
        super(bay);
    }
    superGreet() {
        return this.bay + "!!!"
    }
}
// クラスをインスタンス化
let dog = new Dog("bow wow");
console.log( dog.greet() );
console.log( dog.superGreet() );

ES2015になると、継承を行うための機能である extends キーワードがそのまま使えるためとてもスッキリ書くことができます。

ES2015を使うべきか

ES2015はまだ、対応ブラウザが少ない状況です。(2015年11月現在)
しかし、Babelのようなトランスパイラや、es6-shimといったpolyfillも出てきているため、これらを使うことでES2015で書けるようにもなってきています。

Webアプリやシングルページアプリケーションを実装するときは、必要となるコードの量も必然的に多くなります。
そのときに、ES2015から使えるクラスやその他の便利な機能などを駆使することで、コードが書きやすくなったり可読性があがりコンテンツ制作そのものに今まで以上に集中でき、コンテンツの質も上がるため、私は積極的に使っていきたいと考えています。