メソッドの追加 javascript オブジェクトと関数とコンストラクター関数とインスタンスとprototype

こんにちは！

JavaScript初学者として、ほんの段差2cm、いや、5mm程度位で混乱して躓いた感じですが、
これは今後自分の学習においても、後学におかれましても、確定的な情報として有益だと感じましたので、首題「**メソッドの追加**」について、纏めさせていただきます！

### 実行してみましょう
jsFiddle（https://jsfiddle.net/ ）
JS Bin（https://jsbin.com/?html,js,output ）

### メソッド追加　関数とオブジェクト

次のようにすると上手く行きます。

```javascript
/* 関数オブジェクトfn生成 */
function fn() {
  console.log("fn is called");
}

// プロパティ追加
fn.prop = 0;
/* ★メソッドの追加★ */
fn.method = function () {
  console.log("method is called");
}

// 関数オブジェクト各種出力
fn();
console.log(fn.prop);
fn.method();

/* オブジェクトの生成 */
const tom = {
  name: 'Tom',
  age: 18
}

/* ★メソッドの追加★ */
tom.method = function() {
  console.log("tom method is called");
}

// オブジェクトの各種出力
tom.method();
console.log(tom);
```

>実行結果
```
"fn is called"
0
"method is called"
"tom method is called"
[object Object] {
  age: 18,
  method: function() {
  window.runnerWindow.proxyConsole.log("tom method is called");
},
  name: "Tom"
}
```

### メソッド追加　オブジェクト 上手く行かない Ver.

次のようにすると上手く行きません。

```javascript
/* オブジェクトの生成 */
const tom = {
  name: 'Tom',
  age: 18
}

/* ★メソッドの追加★ */
tom.prototype.proto_method = function() {
  console.log("proto method is called");
}
// オブジェクトの各種出力
tom.proto_method();
console.log(tom);
```

>実行結果
```
"error"
"TypeError: Cannot set properties of undefined (setting 'proto_method')
    at xazoyat.js:8:28
    at https://static.jsbin.com/js/prod/runner-4.1.8.min.js:1:13924
    at https://static.jsbin.com/js/prod/runner-4.1.8.min.js:1:10866"
```

敢えて、オブジェクトtomのprototype(\___proto\__\_)にメソッドを追加したいなら、
こう。
※Web上のドキュメント（https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf ）に、**「Object.setPrototypeOf() メソッドは、指定されたオブジェクトのプロトタイプ (つまり、内部の [[Prototype]]** **プロパティ)を**、**別のオブジェクトまたは** **null** **に設定します。**」とある為、オブジェクトをSetするという発想です。


```javascript
/* オブジェクトの生成 */
const tom = {
  name: 'Tom',
  age: 18
}

const tom_proto = {
  proto_method : function() {
    console.log("proto method is called");
  }
}

/* ★メソッドの追加★ */
Object.setPrototypeOf(tom, tom_proto);
// オブジェクトの各種出力
tom.proto_method();
console.log(tom);
```

>実行結果(Chrome)
```
proto method is called

main.js:17 {name: 'Tom', age: 18}
age: 18
name: "Tom"
[[Prototype]]: Object
proto_method: ƒ ()
[[Prototype]]: Object
```
### メソッド追加　関数 prototype 上手く行かない Ver.

次のようにすると上手く行きません。

```javascript
/* 関数オブジェクトfn生成 */
function fn() {
  console.log("fn is called");
}

/* ★メソッドの追加★ */
fn.prototype.proto_method = function() {
  console.log("proto method is called");
}
// 関数オブジェクト各種出力
fn.proto_method();
```

>実行結果
```
"error"
"TypeError: fn.proto_method is not a function
    at xazoyat.js:11:4
    at https://static.jsbin.com/js/prod/runner-4.1.8.min.js:1:13924
    at https://static.jsbin.com/js/prod/runner-4.1.8.min.js:1:10866"
```
これについては、次のように、コンストラクター関数として把握して、
インスタンスを生成して実行すべき局面。fn⇒Fnになっていることに注意。

```javascript
/* 関数オブジェクトfn生成 */
function Fn() {
  console.log("Fn is called");
}

/* ★メソッドの追加★ */
Fn.prototype.proto_method = function() {
  console.log("proto method is called");
}
/* インスタンス生成 */
const instance = new Fn();
/* インスタンスの各種出力 */
// instance();
instance.proto_method();
```

>実行結果
```
"Fn is called"
"proto method is called"
```

※ちなみに、`instance()`のコメントアウトを外すと、次のようになる。

```javascript
/* 関数オブジェクトfn生成 */
function Fn() {
  console.log("Fn is called");
}

/* ★メソッドの追加★ */
Fn.prototype.proto_method = function() {
  console.log("proto method is called");
}
/* インスタンス生成 */
const instance = new Fn();
/* インスタンスの各種出力 */
instance();
instance.proto_method();
```

>実行結果
```
"Fn is called"
"error"
"TypeError: instance is not a function
    at xazoyat.js:13:1
    at https://static.jsbin.com/js/prod/runner-4.1.8.min.js:1:13924
    at https://static.jsbin.com/js/prod/runner-4.1.8.min.js:1:10866"
```

### まとめ
prototypeはコンストラクター関数で使用し、追加されたメソッドはインスタンスの下に実行可能。
オブジェクトと関数オブジェクトについて、メソッドを追加するに当たって、prototypeは不要。

以上、
数mm、数cmの段差を乗り越えるための記事でした！！