GitBookjs-primerクラス「クラス」と一言にいってもさまざまであるため、ここでは構造、動作、状態を定義できるものを指すことにします。この章では概念を示す場合はクラスと呼び、クラスに関する構文(記述するコード)のことをclass構文と呼びます。クラスとは動作や状態を定義した構造です。クラスからはインスタンスと呼ばれるオブジェクトを作成でき、インスタンスはクラスに定義した動作を継承し、状態は動作によって変化します。抽象的なことに思えますが、これは今までオブジェクトや関数を使って表現してきたものです。JavaScriptではES2015より前まではclass構文はなく、関数を使ってクラスのようなものを表現して扱っていました。ES2015でクラスを表現するためのclass構文が導入されましたが、このclass構文で定義したクラスは関数オブジェクトの一種です。class構文ではプロトタイプベースの継承の仕組みを使って関数でクラスを表現しています。そのため、class構文はクラスを作るための関数定義や継承をパターン化した書き方と言えます。1また、関数の定義方法として関数宣言文と関数式があるように、クラスにもクラス宣言文とクラス式があります。このように関数とクラスは似ている部分が多いです。この章では、class構文でのクラスの定義や継承、クラスの性質について学んでいきます。クラスの定義クラスを定義するにはclass構文を使います。クラスの定義方法にはクラス宣言文とクラス式があります。クラス宣言文によるクラスの定義方法を見ていきます。}のようにクラスの構造を定義できます。クラスは必ずコンストラクタを持ち、constructorという名前のメソッドとして定義します。コンストラクタとは、そのクラスからインスタンスを作成する際にインスタンスに関する状態の初期化を行うメソッドです。constructorメソッドに定義した処理は、クラスをインスタンス化したときに自動的に呼び出されます。}}もうひとつの定義方法であるクラス式は、クラスを値として定義する方法です。クラス式ではクラス名を省略できます。これは関数式における匿名関数と同じです。{}};コンストラクタ関数内で、何も処理がない場合はコンストラクタの記述を省略できます。省略した場合でも自動的に空のコンストラクタが定義されるため、クラスにはコンストラクタが必ず存在します。{}クラスのインスタンス化クラスはnew演算子でインスタンスであるオブジェクトを作成できます。class構文で定義したクラスからインスタンスを作成することをインスタンス化と呼びます。あるインスタンスが指定したクラスから作成されたものかを判定するにはinstanceof演算子が利用できます。trueこのままでは何も処理がない空のクラスなので、値を持ったクラスを定義してみましょう。クラスではインスタンスの初期化処理をコンストラクタ関数で行います。コンストラクタ関数はnew演算子でインスタンス化する際に自動的に呼び出されます。コンストラクタ関数内でのthisはこれから新しく作るインスタンスオブジェクトとなります。次のコードでは、x座標とy座標の値を持つPointというクラスを定義しています。コンストラクタ関数(constructor)の中でインスタンスオブジェクト(this)のxとyプロパティに値を代入して初期化しています。}}このPointクラスのインスタンスを作成するにはnew演算子を使います。new演算子には関数呼び出しと同じように引数を渡すことができます。new演算子の引数はクラスのconstructorメソッド(コンストラクタ関数)の仮引数に渡されます。コンストラクタの中ではインスタンスオブジェクト(this)の初期化処理を行います。4このようにクラスからインスタンスを作成するには必ずnew演算子を使います。クラスは通常の関数として呼ぶことができません。これは、クラスのコンストラクタはインスタンス(this)を初期化する場所であり、通常の関数とは役割が異なるためです。|new|コンストラクタは初期化処理を書く場所であるため、return文で値を返すべきではありません。JavaScriptでは、コンストラクタ関数が任意のオブジェクトを返すことが可能ですが、行うべきではありません。コンストラクタはnew演算子で呼び出し、その評価結果はクラスのインスタンスを期待するのが一般的であるためです。次のコードのようにコンストラクタで返した値がnew演算子で呼び出した際の返り値となります。このような書き方は混乱を生むため避けるべきです。クラス名は大文字ではじめるJavaScriptでは慣習としてクラス名には大文字ではじまる名前をつけます。これは、変数名にキャメルケースを使う慣習があるのと同じで、名前自体に特別なルールがあるわけではありません。クラス名を大文字にしておき、そのインスタンスは小文字で開始すれば名前が被らないという合理的な理由で好まれています。class構文と関数でのクラスの違いES2015より前はこれらのクラスをclass構文ではなく、関数で表現していました。その表現方法は人によってさまざまで、これもclass構文という統一した記法が導入された理由の1つです。次のコードは、関数でクラスを実装した1つの例です。この関数でのクラス表現は、継承の仕組みなどは省かれていますが、class構文とよく似ています。4);大きな違いとして、class構文で定義したクラスは関数として呼び出すことができません。クラスはnew演算子でインスタンス化して使うものなので、これはクラスの誤用を防ぐ仕様です。関数でのクラス表現はただの関数なので、当然関数として呼び出せます。|new|このように、関数でクラスのようなものを実装した場合には、関数として呼び出せてしまう問題があります。このような問題を避けるためにもクラスはclass構文を使って実装します。クラスのプロトタイプメソッドの定義クラスの動作はメソッドによって定義できます。constructorメソッドは初期化時に呼ばれる特殊なメソッドですが、class構文ではクラスに対して自由にメソッドを定義できます。このクラスに定義したメソッドは作成したインスタンスが持つ動作となります。次のようにclass構文ではクラスに対してメソッドを定義できます。メソッドの中からクラスのインスタンスを参照するには、constructorメソッドと同じくthisを使います。このクラスのメソッドにおけるthisは「関数とthis」の章で学んだメソッドと同じくベースオブジェクトを参照します。valueのように:区切りでメソッドを定義できないことに注意してください。次のような書き方は構文エラー(SyntaxError)となります。function(){}}このようにクラスに対して定義したメソッドは、クラスの各インスタンスから共有されるメソッドとなります。このインスタンス間で共有されるメソッドのことをプロトタイプメソッドと呼びます。プロトタイプメソッドはインスタンスから呼び出せるメソッドであるためインスタンスメソッドとも呼ばれます。この書籍では、プロトタイプメソッド(インスタンスメソッド)をクラス#メソッド名のように表記します。次のコードでは、Counterクラスにincrementメソッド(Counter#incrementメソッド)を定義しています。Counterクラスのインスタンスはそれぞれ別々の状態(countプロパティ)を持ちます。0またincrementメソッドはプロトタイプメソッドとして定義されています。プロトタイプメソッドは各インスタンス間で共有されます。そのため、次のように各インスタンスのincrementメソッドの参照先は同じとなっていることがわかります。trueプロトタイプメソッドがなぜインスタンス間で共有されているのかは、クラスの継承の仕組みと密接に関係しています。プロトタイプメソッドの仕組みについては後ほど解説します。クラスのインスタンスに対してメソッドを定義するclass構文でのメソッド定義はプロトタイプメソッドとなり、インスタンス間で共有されます。クラスのインスタンスに対して、直接メソッドを定義する方法もあります。これは、コンストラクタ関数内でインスタンスオブジェクトであるthisに対してメソッドを定義するだけです。次のコードでは、Counterクラスのコンストラクタ関数で、インスタンスオブジェクトにincrementメソッドを定義しています。コンストラクタ関数内でthisはインスタンスオブジェクトを示すため、thisに対してメソッドを定義しています。0この方法で定義したincrementメソッドはインスタンスから呼び出せるため、インスタンスメソッドです。インスタンスオブジェクトに定義したincrementメソッドはプロトタイプメソッドではありません。インスタンスオブジェクトのメソッドとプロトタイプメソッドには、いくつか異なる点があります。プロトタイプメソッドは各インスタンスから共有されているため、各インスタンスからのメソッドの参照先が同じでした。インスタンスオブジェクトのメソッドは、コンストラクタで毎回同じ挙動の関数(オブジェクト)を新しく定義しています。そのため、次のように各インスタンスからのメソッドの参照先も異なります。Functionが利用できます。Functionにはthisが静的に決まるという性質があるため、メソッドにおけるthisの参照先をインスタンスに固定できます。Functionでコールバック関数を扱う」を参照)。instance一方、プロトタイプメソッドにおけるthisはメソッド呼び出し時のベースオブジェクトを参照します。thisを含むメソッドを変数に代入した場合」を参照)。Functionでメソッドを定義することでthisの参照先を固定化できます。クラスのアクセッサプロパティの定義クラスに対してメソッドを定義できますが、メソッドはメソッド名()のように呼び出す必要があります。クラスでは、プロパティの参照(getter)、プロパティへの代入(setter)時に呼び出される特殊なメソッドを定義できます。このメソッドはプロパティのように振る舞うためアクセッサプロパティと呼ばれます。次のコードでは、プロパティの参照(getter)、プロパティへの代入(setter)に対するアクセッサプロパティを定義しています。アクセッサプロパティはメソッド名(プロパティ名)の前にgetまたはsetをつけるだけです。getter(get)には仮引数はありませんが、必ず値を返す必要があります。setter(set)の仮引数にはプロパティへ代入する値が入りますが、値を返す必要はありません。setterが呼び出される次のコードでは、NumberWrapperクラスのvalueプロパティをアクセッサプロパティとして定義しています。valueプロパティへアクセスした際にそれぞれ定義したgetterとsetterが呼ばれているのがわかります。このアクセッサプロパティで実際に読み書きされているのは、NumberWrapperインスタンスの_valueプロパティとなります。プライベートプロパティNumberWrapper#valueのアクセッサプロパティで実際に読み書きしているのは、_valueプロパティです。このように、外から直接読み書きしてほしくないプロパティを_(アンダーバー)で開始するのはただの習慣であるため、構文としての意味はありません。private)を定義する構文はありません。現時点でもWeakSetなどを使うことで疑似的なプライベートプロパティを実現できます。WeakSetについては「Map/Set」の章で解説します。Array#lengthをアクセッサプロパティで再現するgetterやsetterを利用しないと実現が難しいものとしてArray#lengthプロパティがあります。Array#lengthプロパティへ値を代入すると、そのインデックス以降の要素は自動的に削除される仕様になっています。次のコードでは、配列の要素数(lengthプロパティ)を小さくすると配列の要素が削除されています。"このlengthプロパティの挙動を再現するArrayLikeクラスを実装してみます。Array#lengthプロパティは、lengthプロパティへ値を代入した際に次のようなことを行っています。現在要素数より小さな要素数が指定された場合、その要素数を変更し、配列の末尾の要素を削除する現在要素数より大きな要素数が指定された場合、その要素数だけを変更し、配列の実際の要素はそのままにするArrayLike#lengthのsetterで要素の追加や削除を実装することで、配列のようなlengthプロパティを実装できます。"このようにアクセッサプロパティでは、プロパティのようでありながら実際にアクセスした際には他のプロパティと連動する動作を実現できます。静的メソッドインスタンスメソッドは、クラスをインスタンス化して利用します。クラスをインスタンス化せずに利用できる静的メソッド(クラスメソッド)もあります。静的メソッドの定義方法はメソッド名の前に、staticをつけるだけです。静的メソッドの呼び出しクラス.メソッド();次のコードでは、配列をラップするArrayWrapperというクラスを定義しています。ArrayWrapperはコンストラクタの引数として配列を受け取って初期化しています。このクラスに配列ではなく要素そのものを引数に受け取ってインスタンス化できるArrayWrapper.ofという静的メソッドを定義します。3クラスの静的メソッドにおけるthisは、そのクラス自身を参照します。thisと書くこともできます。3このように静的メソッドでのthisはクラス自身を参照するため、クラスのインスタンスは参照できません。そのため静的メソッドは、クラスのインスタンスを作成する処理やクラスに関係する処理を書くために利用されます。2種類のインスタンスメソッドの定義クラスでは、2種類のインスタンスメソッドの定義方法があります。インスタンスオブジェクトに対するメソッドの定義です。これらの2つの方法を同時に使い、1つのクラスに同じ名前でメソッドを2つ定義した場合はどうなるでしょうか?次のコードでは、ConflictClassクラスにプロトタイプメソッドとインスタンスに対して同じmethodという名前のメソッドを定義しています。どちらの`method`が呼び出される?結論から述べると、この場合はインスタンスオブジェクトに定義したmethodが呼び出されます。このとき、インスタンスのmethodプロパティをdelete演算子で削除すると、今度はプロトタイプメソッドのmethodが呼び出されます。"プロトタイプメソッド"この実行結果から次のことがわかります。プロトタイプメソッドとインスタンスオブジェクトのメソッドは上書きされずにどちらも定義されているインスタンスオブジェクトのメソッドがプロトタイプオブジェクトのメソッドよりも優先して呼ばれているどちらも注意深く意識しないと気づきにくいですが、この挙動はJavaScriptの重要な仕組みであるため理解することは重要です。この挙動はプロトタイプオブジェクトと呼ばれる特殊なオブジェクトとプロトタイプチェーンと呼ばれる仕組みで成り立っています。どちらもプロトタイプとついていることからわかるように、2つで1組のような仕組みです。このセクションでは、プロトタイプオブジェクトとプロトタイプチェーンとはどのような仕組みなのかを見ていきます。プロトタイプオブジェクトプロトタイプメソッドとインスタンスオブジェクトのメソッドを同時に定義しても、互いのメソッドは上書きされるわけでありません。プロトタイプメソッドはプロトタイプオブジェクトへ、インスタンスオブジェクトのメソッドはインスタンスオブジェクトへそれぞれ定義されるためです。プロトタイプオブジェクトについては「プロトタイプオブジェクト」の章で簡単に紹介していましたが、改めて解説していきます。プロトタイプオブジェクトとは、JavaScriptの関数オブジェクトのprototypeプロパティに自動的に作成される特殊なオブジェクトです。クラスも一種の関数オブジェクトであるため、自動的にprototypeプロパティにプロトタイプオブジェクトが作成されています。次のコードでは、関数やクラス自身のprototypeプロパティに、プロトタイプオブジェクトが自動的に作成されていることがわかります。trueclass構文のメソッド定義は、このプロトタイプオブジェクトのプロパティとして定義されます。次のコードでは、クラスのメソッドがプロトタイプオブジェクトに定義されていることを確認できます。クラスにはconstructorメソッド(コンストラクタ)が必ず定義されます。このconstructorメソッドもプロトタイプオブジェクトに定義されており、このconstructorプロパティはクラス自身を参照します。trueこのように、プロトタイプメソッドはプロトタイプオブジェクトに定義され、インスタンスオブジェクトのメソッドとは異なるオブジェクトに定義されています。そのため、それぞれの方法でメソッドを定義しても、上書きされることはありません。プロトタイプチェーンclass構文で定義したプロトタイプメソッドはプロトタイプオブジェクトに定義されます。インスタンス(オブジェクト)にはメソッドが定義されていないのに、インスタンスからクラスのプロトタイプメソッドを呼び出せます。"プロトタイプのメソッド"インスタンスからプロトタイプメソッドを呼び出せるのはプロトタイプチェーンと呼ばれる仕組みによるものです。プロトタイプチェーンは2つの処理から成り立ちます。インスタンス作成時に、インスタンスの[[Prototype]]内部プロパティへプロトタイプオブジェクトの参照を保存する処理インスタンスからプロパティ(またはメソッド)を参照するときに、[[Prototype]]内部プロパティまで探索する処理インスタンス作成とプロトタイプチェーンクラスからnew演算子によってインスタンスを作成する際に、インスタンスにはクラスのプロトタイプオブジェクトへの参照が保存されます。このとき、インスタンスからクラスのプロトタイプオブジェクトへの参照は、インスタンスオブジェクトの[[Prototype]]という内部プロパティに保存されます。[[Prototype]]内部プロパティはECMAScriptの仕様で定められた内部的な表現であるため、通常のプロパティのようにはアクセスできません。ここでは説明のために、[[プロパティ名]]という書式でECMAScriptの仕様上に存在する内部プロパティを表現しています。[[Prototype]]内部プロパティへプロパティのようにはアクセスできませんが、Object.getPrototypeOfメソッドで[[Prototype]]内部プロパティを参照できます。次のコードでは、instanceオブジェクトの[[Prototype]]内部プロパティを取得しています。その取得した結果がクラスのプロトタイプオブジェクトを参照していることを確認できます。trueここで重要なのは、インスタンスはどのクラスから作られたかやそのクラスのプロトタイプオブジェクトを知っているということです。[[Prototype]]内部プロパティを読み書きするObject.getPrototypeOf(オブジェクト)でオブジェクトの[[Prototype]]を読み取ることができます。プロトタイプオブジェクト)でオブジェクトの[[Prototype]]にプロトタイプオブジェクトを設定できます。[[Prototype]]内部プロパティを通常のプロパティのように扱える__proto__という特殊なアクセッサプロパティが存在します。これらの[[Prototype]]内部プロパティを直接読み書きすることは通常の用途では行いません。既存のビルトインオブジェクトの動作なども変更できるため、不用意に扱うべきではないでしょう。プロパティの参照とプロトタイプチェーンプロトタイプオブジェクトのプロパティがどのようにインスタンスから参照されるかを見ていきます。オブジェクトのプロパティを参照するときに、オブジェクト自身がプロパティを持っていない場合でも、そこで探索が終わるわけではありません。オブジェクトの[[Prototype]]内部プロパティ(仕様上の内部的なプロパティ)の参照先であるプロトタイプオブジェクトに対しても探索を続けます。これは、スコープに指定した識別子の変数がなかった場合に外側のスコープへと探索するスコープチェーンと良く似た仕組みです。オブジェクトがプロパティを探索するときは次のような順番で、それぞれのオブジェクトを調べます。すべてのオブジェクトにおいて見つからなかった場合の結果はundefinedを返します。instanceオブジェクト自身instanceオブジェクトの[[Prototype]]の参照先(プロトタイプオブジェクト)どこにもなかった場合はundefined次のコードでは、インスタンスオブジェクト自身はmethodプロパティを持っていません。そのため、実際に参照しているのはクラスのプロトタイプオブジェクトのmethodプロパティです。trueこのように、インスタンスオブジェクトにmethodが定義されていなくても、クラスのプロトタイプオブジェクトのmethodを呼び出すことができます。このプロパティを参照する際に、オブジェクト自身から[[Prototype]]内部プロパティへと順番に探す仕組みのことをプロトタイプチェーンと呼びます。プロトタイプチェーンの仕組みを疑似的なコードとして表現すると次のような動きをしています。}}プロトタイプチェーンの仕組みによって、プロトタイプオブジェクトに定義したプロトタイプメソッドをインスタンスから呼び出せます。普段は、プロトタイプオブジェクトやプロトタイプチェーンといった仕組みを意識する必要はありません。class構文はこのようなプロトタイプを意識せずにクラスを利用できるように導入された構文です。プロトタイプベースである言語のJavaScriptではクラスをこのようなプロトタイプを使って表現していることは知っておくとよいでしょう。継承extendsキーワードを使うことで既存のクラスを継承できます。継承とは、クラスの構造や機能を引き継いだ新しいクラスを定義することです。継承したクラスの定義extendsキーワードを使って既存のクラスを継承した新しいクラスを定義してみます。親クラスを継承した子クラス(派生クラス)を定義できます。{}次のコードでは、Parentクラスを継承したChildクラスを定義しています。子クラスであるChildクラスのインスタンス化は通常のクラスと同じくnew演算子を使って行います。Child();superextendsを使って定義した子クラスから親クラスを参照するにはsuperというキーワードを利用します。シンプルなsuperを使う例としてコンストラクタの処理を見ていきます。class構文でも紹介しましたが、クラスは必ずconstructorメソッド(コンストラクタ)を持ちます。これは、継承した子クラスでも同じです。次のコードでは、Parentクラスを継承したChildクラスのコンストラクタで、super()を呼び出しています。super()は子クラスから親クラスのconstructorメソッドを呼び出します。"引数2"class構文でのクラス定義では、constructorメソッド(コンストラクタ)で何も処理しない場合は省略できることを紹介しました。これは、継承した子クラスでも同じです。次のコードのChildクラスのコンストラクタでは、何も処理を行っていません。そのため、Childクラスのconstructorメソッドの定義を省略できます。{}このように子クラスでconstructorを省略した場合は次のように書いた場合と同じ意味になります。constructorメソッドの引数をすべて受け取り、そのままsuperへ引数の順番を維持して渡します。}}コンストラクタの処理順は親クラスから子クラスへコンストラクタの処理順は、親クラスから子クラスへと順番が決まっています。class構文では必ず親クラスのコンストラクタ処理(super()の呼び出し)を先に行い、その次に子クラスのコンストラクタ処理を行います。子クラスのコンストラクタでは、thisを触る前にsuper()で親クラスのコンストラクタ処理を呼び出さないとSyntaxErrorとなるためです。次のコードでは、ParentとChildでそれぞれインスタンス(this)のnameプロパティに値を書き込んでいます。子クラスでは先にsuper()を呼び出してからでないとthisを参照できません。そのため、コンストラクタの処理順はParentからChildという順番に限定されます。次のコードではextendsキーワードを使ってParentクラスを継承したChildクラスを定義しています。Parentクラスではmethodを定義しているため、これを継承しているChildクラスのインスタンスからも呼び出せます。"Parent#method"このように、子クラスのインスタンスから親クラスのプロトタイプメソッドもプロトタイプチェーンの仕組みによって呼び出せます。extendsによって継承した場合、子クラスのプロトタイプオブジェクトの[[Prototype]]内部プロパティには親クラスのプロトタイプオブジェクトが設定されます。このコードでは、Child.prototypeオブジェクトの[[Prototype]]内部プロパティにはParent.prototypeが設定されます。これにより、プロパティを参照する場合には次のような順番でオブジェクトを探索しています。instanceオブジェクト自身Child.prototype(instanceオブジェクトの[[Prototype]]の参照先)Parent.prototype(Child.prototypeオブジェクトの[[Prototype]]の参照先)このプロトタイプチェーンの仕組みにより、methodプロパティはParent.prototypeオブジェクトに定義されたものを参照します。このようにJavaScriptではclass構文とextendsキーワードを使うことでクラスの機能を継承できます。class構文ではプロトタイプオブジェクトを参照する仕組みによって継承が行われています。そのため、この継承の仕組みをプロトタイプ継承と呼びます。静的メソッドの継承インスタンスとクラスのプロトタイプオブジェクトとの間にはプロトタイプチェーンがあります。クラス自身(クラスのコンストラクタ)も親クラス自身(親クラスのコンストラクタ)との間にプロトタイプチェーンがあります。簡単に言えば、静的メソッドも継承されるということです。"Hello"extendsによって継承した場合、子クラスのコンストラクタの[[Prototype]]内部プロパティには親クラスのコンストラクタが設定されます。このコードでは、Childコンストラクタの[[Prototype]]内部プロパティにParentコンストラクタが設定されます。先ほどのコードではChild.helloプロパティを参照した場合には、次のような順番でオブジェクトを探索しています。ChildコンストラクタParentコンストラクタ(Childコンストラクタの[[Prototype]]の参照先)クラスのコンストラクタ同士にもプロトタイプチェーンの仕組みがあるため、子クラスは親クラスの静的メソッドを呼び出せます。superプロパティ子クラスから親クラスのコンストラクタ処理を呼び出すにはsuper()を使います。同じように、子クラスのプロトタイプメソッドからは、super.プロパティ名で親クラスのプロトタイプメソッドを参照できます。次のコードでは、Child#methodの中でsuper.method()と書くことでParent#methodを呼び出しています。このように、子クラスから継承元の親クラスのプロトタイプメソッドはsuper.プロパティ名で参照できます。"Parent#method"プロトタイプチェーンでは、インスタンスからクラス、さらに親のクラスと継承関係をさかのぼるようにメソッドを探索すると紹介しました。このコードではChild#methodが定義されているため、child.methodはChild#methodを呼び出します。Child#methodはsuper.methodを呼び出しているため、Parent#methodが呼び出されます。クラスの静的メソッド同士も同じようにsuper.method()と書くことで呼び出せます。次のコードでは、Parentを継承したChildから親クラスの静的メソッドを呼び出しています。"Parent.method"継承の判定あるクラスが指定したクラスをプロトタイプ継承しているかはinstanceof演算子を使って判定できます。次のコードでは、ChildのインスタンスはChildクラスとParentクラスを継承したオブジェクトであることを確認しています。trueより具体的な継承の使い方については「ユースケース:Todoアプリ」の章で見ていきます。ビルトインオブジェクトの継承ここまで自身が定義したクラスを継承してきましたが、ビルトインオブジェクトのコンストラクタも継承できます。ビルトインオブジェクトにはArray、String、Object、Number、Error、Dateなどのコンストラクタがあります。class構文ではこれらのビルトインオブジェクトを継承できます。次のコードでは、ビルトインオブジェクトであるArrayを継承して独自のメソッドを加えたMyArrayクラスを定義しています。継承したMyArrayはArrayの性質であるメソッドや状態管理についての仕組みを継承しています。継承した性質に加えて、MyArray#firstやMyArray#lastといったアクセッサプロパティを追加しています。5Arrayを継承したMyArrayは、Arrayが元々持つlengthプロパティやArray.fromメソッドなどを継承しているので利用できます。まとめこの章ではクラスについて学びました。class構文でしか実現できない機能はなく、読みやすさやわかりやさのために導入された構文という側面もあるため、JavaScriptのclass構文は糖衣構文(シンタックスシュガー)と呼ばれることがあります。