インスタンスにprototypeは自動設定されない？　無理やり設定した場合は、普通のプロパティとして取り扱われる？


**質問背景**  
・単なる興味本位  
・インスタンスにprototypeは設定できないのかな、と思いました  
・prototypeは予約語ではない(？)ので，普通のプロパティとして使用可能？  
<https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Reserved_Words>

[code]

    var Hoge = function(p1) {
     this.p1 = p1;
    };
    
    Hoge.prototype = {
      m1: function() {
        return this.p1;
      }
    };
    
    var hoge = new Hoge('プ1');
    hoge.m1(); //"プ1"
    
[/code]

* * *

・自動設定されない

[code]

    hoge.prototype; //undefined
    
[/code]

* * *

・インスタンスにprototypeは自動的に設定されないようなので、手動設定に挑戦  
・目的はないです  
・挙動確認したいためだけの単なる興味本位

[code]

    hoge.prototype = {
      m2: function() {
        return this;
      }
    };
    
[/code]

* * *

・Function オブジェクトではないから？

[code]

    hoge.m2(); //Uncaught TypeError: hoge.m2 is not a function(…)
    
[/code]

* * *

・prototypeは予約語ではない(？)ので，普通のプロパティとして使用可能、ということでしょうか？

[code]

    hoge.prototype.m2(); //Object {}
    
[/code]




ややこしいので、以下ではオブジェクトがプロパティを継承するオブジェクトを「プロトタイプ」、名前がたまたまprototypeであるプロパティを「prototypeプロパティ」と書きます。

オブジェクトの「prototypeプロパティ」は、そのオブジェクトの「プロトタイプ」ではありません。  
おっしゃる通り、「prototypeプロパティ」は普通のプロパティです。  
プロトタイプチェーンで「prototypeプロパティ」が参照される事はありません。  
質問の例ですと、Hogeは「prototypeプロパティ」の m1 がありますが、m1 という名前でプロパティを参照しても、これは辿られません。

[code]

    Hoge.prototype;
    // -> { m1: [Function] }
    Hoge.m1();
    // エラー
    
[/code]

では、Hogeのプロトタイプテェーンで参照される「プロトタイプ」は何なのかというと、`Object.getPrototypeOf(Hoge)`
で調べられます。Hogeは関数なので定義した時に処理系が`Function.prototype`を自動で設定しています。callプロパティ（メソッド）を調べると、プロトタイプテェーンでFunction.prototype.callが辿られているのが分かります。

[code]

    Object.getPrototypeOf(Hoge) === Function.prototype
    // -> true
    Hoge.call == Function.prototype.call
    // -> true
    
[/code]

では、「prototypeプロパティ」が普通のプロパティであるなら、いつ使われるかというと、new演算子がオブジェクトを作る時です。new
は新しいオブジェクトの「プロトタイプ」にコンストラクタオブジェクトの「prototypeプロパティ」を設定します。

[code]

    hoge = new Hoge(1);
    Hoge.prototype === Object.getPrototypeOf(hoge);
    // -> true
    
[/code]

このように、new が使う約束になっている事以外は「prototypeプロパティ」に特別な作用はないのです。

ただ、さらにややこしい事にブラウザによっては「__proto__プロパティ」という物があります。  
これは本当にオブジェクトの「プロトタイプ」を参照しており、場合によって設定し直す事も可能です。

[code]

    hoge.__proto__ = {
      m2: function() {
        return this;
      }
    };
    
    hoge.m2()
    // -> Object { p1: "プ1" }
    hoge.m1()
    // エラー: 
    // hogeの「プロトタイプ」をnew演算子が設定した物(Hogeの「prototypeプロパティ」)
    // と入れ替えたため。m1は辿れなくなった。
    
[/code]

「__proto__プロパティ」は標準でなく（後から書き換えが可能な事から性能上の問題もあるらしいです）、使うべきではありません。




ややこしいので、以下ではオブジェクトがプロパティを継承するオブジェクトを「プロトタイプ」、名前がたまたまprototypeであるプロパティを「prototypeプロパティ」と書きます。

オブジェクトの「prototypeプロパティ」は、そのオブジェクトの「プロトタイプ」ではありません。  
おっしゃる通り、「prototypeプロパティ」は普通のプロパティです。  
プロトタイプチェーンで「prototypeプロパティ」が参照される事はありません。  
質問の例ですと、Hogeは「prototypeプロパティ」の m1 がありますが、m1 という名前でプロパティを参照しても、これは辿られません。

[code]

    Hoge.prototype;
    // -> { m1: [Function] }
    Hoge.m1();
    // エラー
    
[/code]

では、Hogeのプロトタイプテェーンで参照される「プロトタイプ」は何なのかというと、`Object.getPrototypeOf(Hoge)`
で調べられます。Hogeは関数なので定義した時に処理系が`Function.prototype`を自動で設定しています。callプロパティ（メソッド）を調べると、プロトタイプテェーンでFunction.prototype.callが辿られているのが分かります。

[code]

    Object.getPrototypeOf(Hoge) === Function.prototype
    // -> true
    Hoge.call == Function.prototype.call
    // -> true
    
[/code]

では、「prototypeプロパティ」が普通のプロパティであるなら、いつ使われるかというと、new演算子がオブジェクトを作る時です。new
は新しいオブジェクトの「プロトタイプ」にコンストラクタオブジェクトの「prototypeプロパティ」を設定します。

[code]

    hoge = new Hoge(1);
    Hoge.prototype === Object.getPrototypeOf(hoge);
    // -> true
    
[/code]

このように、new が使う約束になっている事以外は「prototypeプロパティ」に特別な作用はないのです。

ただ、さらにややこしい事にブラウザによっては「__proto__プロパティ」という物があります。  
これは本当にオブジェクトの「プロトタイプ」を参照しており、場合によって設定し直す事も可能です。

[code]

    hoge.__proto__ = {
      m2: function() {
        return this;
      }
    };
    
    hoge.m2()
    // -> Object { p1: "プ1" }
    hoge.m1()
    // エラー: 
    // hogeの「プロトタイプ」をnew演算子が設定した物(Hogeの「prototypeプロパティ」)
    // と入れ替えたため。m1は辿れなくなった。
    
[/code]

「__proto__プロパティ」は標準でなく（後から書き換えが可能な事から性能上の問題もあるらしいです）、使うべきではありません。

