質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

1回答

1098閲覧

ES2015の子クラスの constructor() では、なぜ super() を呼ぶ必要があるのか?

ku__ra__ge

総合スコア4524

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

5グッド

3クリップ

投稿2018/01/11 10:32

ES5で子クラスのような動きをするコードでは super() に該当するコードを呼ぶことは必須ではありませんが、ES2015ではそれがないとエラーが発生します。
ES2015の子クラスの constructor() では、なぜ super() を最初に呼ぶ必要があるのでしょうか?

親クラスのコンストラクタが呼ばれていないのは、オブジェクトの状態として変だからでしょうか?
であればなぜ暗黙に呼ばれるのではなく、明示的に記述しなければエラーが発生するようになっているのでしょうか?

ES5

1var Parent = function () { console.log("Parent constructor"); }; 2Parent.prototype.parentMethod = function() { console.log("parentMethod"); } 3 4var Child = function () { console.log("Child constructor"); }; 5Child.prototype = Object.create(Parent.prototype); 6Child.prototype.constructor = Child; 7Child.prototype.childMethod = function() { console.log("childMethod"); } 8 9var c = new Child(); // エラーは発生しない

ES2015

1class Parent { 2 constructor() { console.log("Parent constructor"); } 3 parentMethod() { console.log("parentMethod"); } 4} 5class Child extends Parent { 6 constructor() { console.log("Child constructor"); } // super() を呼んでいないためエラーになる 7 parentMethod() { console.log("childMethod"); } 8} 9var c = new Child(); // ReferenceError: |this| used uninitialized in Child class constructor
Lhankor_Mhy, sota_u, shuntksh, umyu, KSwordOfHaste👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

https://stackoverflow.com/questions/31067368/javascript-es6-class-extend-without-super

にES2015でなぜsuperを呼ぶ仕様になっているかに関する回答があるようです。

派生クラスを定義する場合、(おそらく継承ベースのオブジェクト指向言語ではないためだと思いますが)クラスのコンストラクターにはどのようなオブジェクトを生成するかについて選択肢があるようです。

(A)一つはそのクラスの所謂インスタンスを生成することで、
(B)もう一つはそのクラスのインスタンスでないものを生成することです

(A)のパターンではnew Child() instanceof Childはtrueですが、(B)ではそうなるとは限りません。

(A)(B)どちらであるかはコンストラクター内で何かをreturnしているかどうかによりコンパイラーが判断するようで、returnがないなら(A)であると見做されるということだと思います。

さて(A)ではインスタンスが正しく初期化されていることが前提になるとのことですが、言語仕様により基底クラスがあるならsuper()を呼び出して初めてthisは初期化済みになるようです。そして(A)のパターンではコンストラクター内部で必ずthisが初期化状態になっていなければならないという仕様ですね。その仕様は自然に感じます。

もっとも、この辺り継承ベースのオブジェクト指向言語でよくある「基底クラスのコンストラクターに引数がないなら省略できる」という仕様とは違うのは質問者さんがおっしゃるとおりですね。「引数を必要としないならsuper()をconstructorの先頭で暗黙的に呼び出すという意味にしてくれてもいいんじゃないか」という意見もうなずけます。

ただjavascriptの場合はコンストラクターも含めて関数呼び出し時に仮引数と実引数の一致を要求しない言語仕様のため

  • 基底クラスのコンストラクターに引数がないから呼び出していないのか
  • 基底クラスのコンストラクターに引数があるがそれを無視して引数を渡さないのがプログラマーの意志なのか
  • プログラマーが単にsuperを呼び出し忘れているのか

がはっきりしないのではないでしょうか?そのためせめてsuperを明示的に呼び出さないといけないという仕様にしているのかな・・・と想像しました。実際のところどうなのかはっきりわかりませんが、少なくとも上記のような理由なら自分には納得いくように感じました。

正確な仕様の経緯を把握していないコメントで申し訳ないです。

投稿2018/01/11 11:47

編集2018/01/11 11:54
KSwordOfHaste

総合スコア18394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ku__ra__ge

2018/01/13 06:02

なるほど、関数呼び出し時に仮引数と実引数の一致を要求しない言語仕様のためというのは理由としてありそうですね。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問