59
42

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ES2015(ES6)の子クラスの constructor() では super() が必須で、super()の前には this.* や super.* が使えない話

Last updated at Posted at 2016-02-24

TL;DR

タイトルのままです。

背景:よく出会うエラー

  1. SyntaxError: missing super() call in constructor
  2. SyntaxError: 'this' is not allowed before super()
  3. SyntaxError: 'super.*' is not allowed before super()

1. 子クラスのconstructor()ではsuper()呼び出しが必須

エラーになるコード例

こういうコードはエラーになります。

missing-super-error.js
class Parent {
}

class Child extends Parent {
  constructor() {}
}

解決・解消コード例

super()を追加します。

fix-missing-super-error.js
class Parent {
}

class Child extends Parent {
  constructor() { super(); }
}

または特にコンストラクタで何もしないなら、constructor()自体を削除してしまいましょう。

fix-missing-super-error.js
class Parent {
}

class Child extends Parent {
}

これは、デフォルトで以下のように書いたのと同じです。

default-subclass-constructor.js
class Child extends Parent {
  constructor(...args) { super(...args); }
}

ちなみにこのコードは、new Child()したときの引数をそのまま親クラスのコンストラクタへ引数として渡します。

2. 子クラスのconstructor()ではsuper()の前でthisを参照することはできない

エラーになるコード例

こういうコードは、どの子クラス定義でもエラーになります。

this-before-super-error.js
class Parent {}

class Child01 extends Parent {
  constructor(params) {
    // super()の前で自プロパティへ代入
    this.params = params;
    super();
  }
}

class Child02 extends Parent {
  constructor(params) {
    // super()の前で自クラスのメソッドを呼ぶ
    const processed_params = this.preprocessing(params);
    super(processed_params);
  }

  preprocessing(params) {
    // process something
  }
}

解決・解消コード例

基本的にはsuper()呼び出しより後にthis.*を移動させると良いでしょう。

fix-this-before-supper-error.js
class Child01 extends Parent {
  constructor(params) {
    super();
    this.params = params;
  }
}

Child02クラスのように、自クラスのメソッドの結果をsuper()に渡している場合は前後入れ換えで解決しませんが、このようなケースではクラス設計に間違いがある場合がほとんどです。

fix-this-before-supper-error.js
class Child02 extends Parent {
  constructor(params) {
    super(params);
    this.preprocessing();
  }
}

上記のように引数をそのまま渡してsuper()を呼び、その後に自インスタンスを加工するという順番にできないか検討してみましょう。

ちなみに、super()の戻り値と、super()の後で参照できるthisは同じものです。

compare-instance-with-this.js
class Parent {}

class Child02 extends Parent {
  constructor() {
    const instance = super();
    console.log(instance === this); // => true
  }
}

new Child02();

3. 子クラスのconstructor()ではsuper()の前でsuper.*(親クラス呼び出し)はできない

エラーになるコード例

こういうコードは、どの子クラス定義でもエラーになります。

super-before-super-error.js
class Parent {
  processing(params) {
    // process something
  }
  get name() { return 'NAME'; }
}

class Child01 extends Parent {
  constructor(params) {
    // 親クラスのプロパティを参照する
    const name = super.name + params;
    super();
  }
}

class Child02 extends Parent {
  constructor(params) {
    // 親クラスのメソッドを呼ぶ
    const processed_params = super.processing(params);
    super(processed_params);
  }
}

解決・解消コード例

これらもthisのときと同様、基本的にはsuper()を先に呼ぶようにします。

fix-super-before-super-error.js
class Child01 extends Parent {
  constructor(params) {
    super();
    const name = super.name + params;
  }
}

Child02のように親クラスのメソッドの実行結果をsuper()の引数として渡している場合は、thisのときと同じようにクラス設計を見直して、親クラスのconstructor()の方にprocessing()実行を移動させてしまうのが良いでしょう。

fix-super-before-super-error.js
class Parent {
  constructor(params) {
    this.processed_params = this.processing(params);
  }
  processing(params) {
    // process something
  }
}

class Child02 extends Parent {
  constructor(params) {
    super(params);
	this.processed_params
  }
}

以上です。役に立ちそうでしたら「ストック」してもらえると嬉しいです。
それでは、良いES6ライフをお過ごしください。

59
42
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
59
42

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?