[Avascript]ClassとPrototype


まず、JavaScriptでClassとPrototypeを紹介する前に、いくつかの重要な事実を理解しておきましょう.
実際,文法的にはJavaScriptにはクラスが存在するが,実際にはクラスは存在しない.
どういう意味か知るためにまずClassを知っておく

Class


クラスとは、通常、オブジェクト向けプログラミングでオブジェクトを印刷するフレームワークを指す.
ECMAScript 2015はいくつかのキーワードを導入し、同時にClassも導入した.
しかし,このとき導入されるクラスは,既存のオブジェクト向けプログラミング言語におけるクラスとは異なる動作方式を持つ.実際、JavaScriptでは、クラスはPrototypeに基づいており、他の言語のクラスとは異なります.
次の例は、JavaScriptでClassを使用する例です.
'use strict'

class Cadet {
  constructor(intraID) {
    this.intraID = intraID;
  }
}
このコードは文法的にはこのように書かれていますが、実際には
function Cadet(intraID) {
  this.intraID = intraID;
}
こんなコードになる
次のコードに変換して実行すると、値が返されず、オブジェクトがどのように作成されたかが疑われる可能性があります.
JavaScriptでは、関数がnew演算子に遭遇すると不思議な現象が発生します.まず、メモリに新しい空のオブジェクトを作成します.次に、空のオブジェクトを関数のthisにバインドし、オブジェクトのプロパティを塗りつぶす操作を実行します.最後に、関数にreturnが存在しない場合はthisを返します.
次に、クラスの継承を見てみましょう.
'use strict'

class Cadet {
  constructor(intraID) {
    this.intraID = intraID;
  }
}

class CadetStduyingJS extends Cadet{ // Cadet을 상속하는 CadetStduyingJS클래스
  constructor(intraID) {
    super(intraID);
  }
  
  doStudy() {
    console.log("i'm studying JS);
  }
}
典型的なオブジェクト向けプログラミングでは、継承は親クラスの内容を子クラスにコピーして継承します.
しかし、JavaScriptはこのように継承されません.
JavaScriptでは元の値とオブジェクトの参照値しかコピーできないため、親のコンテンツは子のコンテンツにコピーできません.
したがって、Javascriptでは、クラスやオブジェクトのコンテンツをコピーすることなくPrototypeを使用して継承を実現します.

Prototype


Prototypeは、JavaScriptで継承を実現する方法で、他の言語のようにコンテンツをコピーすることによって継承するのではなく、オブジェクトとオブジェクト間の接続という特性を使用します.
次の画像は、ブラウザコンソールの画面に表示されるプロトタイプです.


特定のオブジェクトに直接アクセスしないプロトタイプオブジェクトの正式な方法-Javascript言語標準仕様では、「リンク」は内部属性によって定義され、「プロトタイプ」として表されるプロトタイプオブジェクトです.(ECMAScriptを参照).しかし、多くの現代ブラウザでは、__proto__(en-US)(前後各2つの下欄)属性を介して特定のオブジェクトにアクセスするプロトタイプオブジェクトが実現されている.たとえば、チェーンがperson1.__proto__またはperson1.__proto__.__proto__のコードから構成されていることを確認してください.MDN - ProtoType
継承は__proto__という属性を使用して実現され、リンクはオブジェクトとオブジェクトのリンクである.
オブジェクトに関連付けられたリンクは、大きく分けて3つに分類されます.
まず、オブジェクトが他のオブジェクトに基づいて作成された場合、オブジェクトはそのプロトタイプへの__proto__リンクを自動的に有します.
const newObj = Object.create(oldObj)
newObj.__proto__ === oldObj
次のオブジェクトがオブジェクトではなく関数オブジェクトの場合、__proto__ではなく関数の他のプロトタイプオブジェクトが作成されます.関数のprototypeプロパティは、作成されたprototypeオブジェクトを指し、prototypeオブジェクトはconstructorプロパティを介して関数のループ参照関係を指します.

オブジェクトが最後にnew+関数によって作成された場合、作成されたオブジェクトの__proto__リンクは、その関数のプロトタイプオブジェクトを指します.
function sayJS() {
  console.log(`${this.intraID} saying JS!`);
}

function Cadet(intraID) {
  this.intraID = intraID;
}

Cadet.prototype.sayJS = sayJS;

const byoo = new Cadet('byoo');

byoo.sayJS();
では、次のコードで、最後のbyooオブジェクトがsayJS関数を呼び出すと、何が起こるのでしょうか.
このとき、プロトタイプフィルタということが起こります.__proto__リンクを使用してプロトコルタイプを参照すると、プロトコルタイプフィルタが発生します.
byooオブジェクトからsayJS関数を呼び出すと、まずbyooオブジェクトにsayJS関数があるかどうかをチェックします.sayJS関数はbyooオブジェクトには存在しませんが、終了しません.__proto__リンクでbyooオブジェクトのCate関数を作成したPrototypeオブジェクトに移動し、sayJS関数を検索します.この場合、sayJS関数があるため、sayJS関数がアクティブになります.

プロトタイプ充填はprototypeを介して行われ、__proto__の値を持つオブジェクト(元のオブジェクト)が現れるとプロトタイプチェーンは停止します.
JavaScriptはプロトタイプベースの言語です.Prototypeを使用してオブジェクト間の継承関係を表し、コピーハンドルではなくPrototypeチェーンを使用して、他の言語で使用されている継承に関連するオブジェクトを検索します.
では、コードを修正して、次のように修正するとどうなりますか?
function sayJS() {
  console.log(`${this.intraID} saying JS!`);
}

function Cadet(intraID) {
  this.intraID = intraID;
}

Cadet.prototype.sayJS = sayJS;

const byoo = new Cadet('byoo');

byoo.sayJS = function(){
  console.log('byoo saying JS!');
}

byoo.sayJS();
このコードは、場合によっては異なる操作を実行します.
まず、最初の状況を見てみましょう.
Object.defineProperty(Cadet.prototpye, "sayJS", {
                      writable: false
  					  ...
})
Cateプロトタイプオブジェクトに追加されたsayJS関数が読み取り専用の場合、厳格モードではエラーが発生しますが、非厳格モードでは何も起こりません.
通常、sayJS関数が読み取り専用でない場合.
Object.defineProperty(Cadet.prototpye, "sayJS", {
                      writable: true
  					  ...
})
属性としてsayJS関数をbyooオブジェクトに追加します.したがって、byooオブジェクトは、既存のプロトコルタイプフィルタによって使用されるsayJS関数にアクセスする方法を失うことになります.
同じ名前の関数をアトリビュートに追加すると、既存の関数は使用できません.Javascriptではこのようなメソッドオーバーライドは存在しませんが、マスクを使用すると同様の操作が可能になります.