プロトタイプメソッドを参照
クラスにメソッドが予め定義されていて、そのメソッドをそのクラスのインスタンスオブジェクトが参照する時は「プロトタイプメソッド」を参照しています。
// es5-------
function Sam(){
this.samMethod = function() {
console.log("samMethod")
}
}
let a = new Sam()
// プロトタイプメソッドを参照
a.samMethod() // "samMethod"
// es2015-------
class Sam{
samMethod(){
console.log("samMethod")
}
}
let a = new Sam()
// プロトタイプメソッドを参照
a.samMethod() // "samMethod"
以下のように表します。
// Sam.prototype.samMethod
console.log(Sam.prototype.samMethod) // [Function: samMethod]
※)prototype の代わりに「#」を用いて、Sam#samMethod と書く事もできます。
以下のようにした場合は未定義となりますので、「プロトタイプメソッド」を参照している事が解ります。
console.log(Sam.samMethod) // undefined
すべての関数は prototype を持っている
javascript では、すべての関数は prototype と呼ばれる特別なプロパティを持っています。
またjavascript では、クラスは関数として扱われます。なので es2015 からの class キーワードで宣言したクラスも prototype プロパティを持つことになります。
※)classキーワードは「糖衣構文」の役目をしているだけです。
// コンストラクタ(関数)
function Sam1(){
this.samMethod = function() {
console.log("samMethod")
}
}
class Sam2{
samMethod() {
console.log("samMethod")
}
}
console.log(typeof Sam1) // function
console.log(typeof Sam2) // function
仕組みとしては、new を使って新たに生成されたインスタンスオブジェクトはコンストラクタ(関数)の prototype オブジェクトにアクセスできます。そしてインスタンスオブジェクトはこれをプロパティ __proto__ に保存します。
javascript では、すべてのオブジェクトは自動的に __proto__ を保持しているのでインスタンスオブジェクトも保持する事になり、そこに prototype オブジェクトを保存するという事になります。
インスタンスオブジェクトはprototype オブジェクトを保存(保持)することになり、関数の持っている prototype プロパティへのアクセスが可能になります。
以下のコードからもインスタンスオブジェクトがprototype オブジェクトを保存している事が解ります。
function Sam(){
this.a = 10
// プロトタイプ参照のメソッド(Sam.prototype.samMethod)
this.samMethod = function() {
console.log("プロトタイプのsamMethod")
}
}
let a = new Sam()
console.log(a.__proto__) // {}
console.log(Sam.prototype) // {}
console.log(a.__proto__ === Sam.prototype) // true
prototype チェーン
prototype チェーンとは、(インスタンス)オブジェクトがプロパティや関数を持っていない場合、__proto__ が保存するコンストラクタ(関数)の prototype オブジェクトにさかのぼって探すことをいいます。
以下のコードのメソッドへのアクセスは、まず(インスタンス)オブジェクトの持つメソッドへのアクセスを優先し、そのメソッドが無ければ、その(インスタンス)オブジェクトの保存(保持)しているプロトタイプをチェックし、同じ名前のメソッドが存在していればそのメソッドにアクセスします。
function Sam(){
// プロトタイプ参照のメソッド(Sam.prototype.samMethod)
this.samMethod = function() {
console.log("プロトタイプのsamMethod")
}
}
let a = new Sam()
// こちらが優先される
a.samMethod = function(){
console.log("aインスタンスのsamMethod")
}
a.samMethod() // aインスタンスのsamMethod
(インスタンス)オブジェクトの持つメソッドが存在しない場合、プロトタイプ参照のメソッドへアクセスします。
function Sam(){
// プロトタイプ参照のメソッド(Sam.prototype.samMethod)
this.samMethod = function() {
console.log("プロトタイプのsamMethod")
}
}
let a = new Sam()
a.samMethod() // プロトタイプのsamMethod
a(インスタンス)オブジェクトに設定されたメソッドは、他のインスタンスからはアクセスできません。
プロトタイプ参照のメソッドは全てのインスタンスオブジェクトからアクセス可能です。
function Sam(){
// プロトタイプ参照のメソッド(Sam.prototype.samMethod)
this.samMethod = function() {
console.log("プロトタイプのsamMethod")
}
}
let a = new Sam()
let b = new Sam()
// aからのみアクセス可能
a.samMethod = function(){
console.log("aインスタンスのsamMethod")
}
a.samMethod() // aインスタンスのsamMetho
b.samMethod() // プロトタイプのsamMethod
プロパティに関しても同じです。
function Sam(){
this.pro = 10
}
let a = new Sam()
let b = new Sam()
a.pro = 20
console.log(a.pro) // 20
console.log(b.pro) // 10