WebDesign Dackel

Babel6でクラス継承をIE9に対応する

Hatena0
Google+0
Pocket0
Feedly0

Babel6を使ってクラスの継承をトランスパイルする際に、継承先クラスのコンストラクタでsuper()を使い親コンストラクタを呼び出すと、IE9で正しく動作しませんでした。

そもそもIE9で動作させるというのが最近では減ってきているし辛い点ではありますが、そうも言ってられない場合もあるので、その時の対応についてメモです。

最小の再現コード

とてもシンプルなコードで試してみます。

class Parent {
  constructor() {
    console.log("Parent::constructor");
  }
}

class Child extends Parent {
  constructor() {
    super();
    console.log("Child::constructor");
  }
}

new Child();

.babelrcの設定は以下。

{
  "presets": ["es2015"]
}

presetsbabel-preset-es2015を指定しているだけで変わったところはありません。


上記をトランスパイル後、IE9で実行すると親コンストラクタが無視され以下のような内容がコンソールに出力されます。

Child::constructor

looseオプションの適用で対応する

上記の問題を解決するために、transform-es2015-classesをはじめとした幾つかのBabelプラグインに対し、looseオプションを指定する必要があるみたいです。

babel-preset-es2015が導入済みの場合、代わりにbabel-preset-es2015-looseを使うことで簡単に対応できます。

bkonkle/babel-preset-es2015-loose

まずはpresetsをインストールします。

$ npm i -D babel-preset-es2015-loose

次に.babelrcを以下のように書き換えます。

{
  "presets": ["es2015-loose"]
}

設定を変更し、再度トランスパイルを実行後IE9でコンソールを確認すると、期待した通りの内容が出力されました。

Parent::constructor
Child::constructor

トランスパイル後のコードを確認してみる

looseを使用した場合と、そうでない場合で、コードの内容はほとんど同じでしたが、コンストラクタの呼び出し部分がObject.getPrototypeOfの代わりに、コンテキストを束縛した状態で親のクラス(関数)を呼び出すように変更されていました。

--- es2015の場合
+++ es2015-looseの場合
@@ -18,7 +18,7 @@
   function Child() {
     _classCallCheck(this, Child);

-    var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(Child).call(this));
+    var _this = _possibleConstructorReturn(this, _Parent.call(this));

     console.log("Child#constructor");
     return _this;