prototypeとclassを理解する
JavaScriptの継承は、見つからないプロパティを別のオブジェクトへ探しに行く仕組みです。所有プロパティ、プロトタイプ、コンストラクタ、class記法を具体的な探索順でつなげます。
この単元で学ぶこと
- 所有と継承のプロパティを区別する
- newとprototypeの関係を説明する
- classの実体メソッドとstaticを使い分ける
本文解説
オブジェクトとプロパティ const item={name:"pen",price:120};は二つの所有プロパティを持つオブジェクトです。item.priceは120、item["name"]はpenです。オブジェクトは値を持つプロパティの集合であり、関数も値として保存できます。値の読取り、代入、削除、存在検査は違う操作です。ここでは通常の書込み可能なデータプロパティを使い、getterやProxyの特別な動作は入れません。
プロトタイプをたどる const p={n:3};const a=Object.create(p);ではa自身にnはありません。それでもa.nは3です。読取りは自分自身を探し、なければ直接のプロトタイプp、その先へ進み、最後のnullまで見つからなければundefinedになります。これはプロパティをaへコピーする操作ではありません。
所有値で親を隠す a.n=8とすると、この例ではaの所有プロパティnが作られます。a.nは8でp.nは3のままです。同名の所有値が探索で先に見つかるため、継承値が見えなくなることをシャドーイングといいます。delete a.nで所有値を消すと再びp.nの3が見えます。親まで同時に削除されません。
存在を何の範囲で調べるか "n" in aは継承分も含めて探します。Object.prototype.hasOwnProperty.call(a,"n")はa自身にあるかだけを返します。Object.keys(a)は所有かつ列挙可能な文字列キーの配列です。Object.create(null)や同名メソッドの上書きがあるオブジェクトにも対応するため、ここではhasOwnPropertyをObject.prototypeから借用します。
コンストラクタとprototype function Item(n){this.n=n;}をnew Item(4)で呼ぶと、生成実体の直接のプロトタイプは通常Item.prototypeです。Item.prototype.read=function(){return this.n;}を設定すれば複数の実体がreadという同じ関数を共有できます。一方nは各実体へ代入しているため個別です。ItemそのものとItem.prototypeは別のオブジェクトです。
classで同じ関係を書く class Item{constructor(n){this.n=n;} read(){return this.n;}}では、new Item(6).read()は6です。constructorは生成時の初期化、通常のreadはItem.prototype上のメソッドです。classにはnewが必要で、通常関数のようにItem()と呼ぶとTypeErrorです。classメソッドの本体はstrictとして実行されます。
staticはクラス側の操作 class Item{static kind(){return "item";}}ならItem.kind()が呼出し方です。new Item().kindは通常undefinedであり、実体のメソッドにはなりません。実体ごとの状態を扱うreadと、クラス全体に関する操作kindを置く場所の違いです。staticという名前だけで結果が共有保存されるわけではなく、定義した処理をクラス側から呼べるという意味です。
継承先を直接確認する Object.getPrototypeOf(a)はaの直接のプロトタイプを返します。a=Object.create(p)なら戻り値はpです。Object.create(null)には継承先がなく、toStringなども自動ではありません。図を書くときは「実体→Item.prototype→Object.prototype→null」という参照の矢印と、「実体自身が持つn」を分けて置くと、共有と個別の境界が見えます。
図解
重要ポイント
- プロパティ探索は自身からプロトタイプへ進む。
- 代入・削除で所有プロパティと継承値の見え方が変わる。
- 通常のclassメソッドはprototype上に置かれる。
- staticはクラス側に置かれる。
間違えやすい点
- inと所有判定を混同しない。
- ItemとItem.prototypeを同じ実体と考えない。
- 継承を単純な値のコピーと考えない。
用語解説
- プロトタイプ
- 自分にないプロパティを探すときに参照する別のオブジェクト。
- 所有プロパティ
- 継承先でなく、そのオブジェクト自身に定義されたプロパティ。
- シャドーイング
- 同名の所有プロパティが先に見つかり、継承先の値を隠すこと。
関連教材
参考資料
教材データに登録された参考リンクです。リンク先の内容や更新日は提供元でご確認ください。
- https://html5exam.jp/outline/objectives_lv2.html
- https://tc39.es/ecma262/2024/multipage/ordinary-and-exotic-objects-behaviours.html#sec-ordinarycallbindthis
- https://tc39.es/ecma262/2024/multipage/ecmascript-language-functions-and-classes.html#sec-class-definitions
- https://tc39.es/ecma262/2024/multipage/ecmascript-language-statements-and-declarations.html#sec-try-statement
確認問題の出題・採点や学習履歴の保存にはログインが必要です。