【JavaScript】関数とオブジェクト⑭　プロトタイプチェーン



#はじめに

Udemyの[【JS】ガチで学びたい人のためのJavaScriptメカニズム](https://www.udemy.com/course/javascript-essence/)の講座の振り返りです。

前回の記事

https://qiita.com/nao0725/items/fa058f7c761faf782703

#目的

* 関数とオブジェクトについての理解を深める

#本題
###1.プロトタイプチェーン

プロトタイプを多重形成したもの

どういうことかコードで確認します。


####例1

前提として

````js
function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.hello = function() {
  console.log('hello ' + this.name);
}
//  インスタンス化
const bob = new Person('Bob', 18);
bob.hello();
````

上記の状態でコンソールにbobを入れると

````実行結果.
bob
Person {name: 'Bob', age: 18}
````

さらにPersonの中身を確認すると

````実行結果.
Person {name: 'Bob', age: 18}
 age: 18
 name: "Bob"
 [[Prototype]]: Object
   hello: ƒ ()
   constructor: ƒ Person(name, age)
   [[Prototype]]: Object
     constructor: ƒ Object()
             :
             :
````

上記のようにPrototypeが多階層に連なっている状態をプロトタイプチェーンという

####例2

このような状態だとどのようなことがおこるのか

````js
function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.hello = function() {
  // 下記の出力結果と混同しないように名前をつける
  console.log("Person: hello" + this.name);
}

// もう一個プロトタイプを用意
Object.prototype.hello = function() {
  console.log('Object: hello ' + this.name);
}

const bob = new Person('Bob', 18);
// 上記の状態で出力するともちろんPersonが呼ばれるようになる
bob.hello();
````

しかし、Personの方をコメントアウトすると

````js
function Person(name, age) {
  this.name = name;
  this.age = age;
}

// Person.prototype.hello = function() {
//   // 下記の出力結果と混同しないように名前をつける
//   console.log("Person: hello" + this.name);
// }

// こっちのプロトタイプが呼ばれる
Object.prototype.hello = function() {
  console.log('Object: hello ' + this.name);
}

const bob = new Person('Bob', 18);
// プロトタイプの階層の浅いものから探しにいく
// 今回は出力結果にPersonが見つからなかったので、次にObjectを探している
bob.hello();
``````

```実行結果.
bob
 Person {name: 'Bob', age: 18}
  age: 18
  name: "Bob"
   [[Prototype]]: Object
    constructor: ƒ Person(name, age)
    [[Prototype]]: Object
      hello: ƒ () ←　Objectの中にhelloを発見
`````

優先順位の高いほうが呼ばれている　

####例3

this.helloが関数内にあった場合

````js
function Person(name, age) {
  this.name = name;
  this.age = age;
  // this.helloに関数を入れる
  this.hello = function() {
    // 下記と区別するためにOwnPropertyを作成
    console.log('OwnProperty: hello ' + this.name);
  }
}

// Person.prototype.hello = function() {
//   // 下記の出力結果と混同しないように名前をつける
//   console.log("Person: hello" + this.name);
// }

Object.prototype.hello = function() {
  console.log('Object: hello ' + this.name);
}

const bob = new Person('Bob', 18);
// この結果の出力はOwnProperty: hello Bobとなる
//　自身のプロパティでhelloが見つかったから
// 自分のプロパティ　→　コンストラクター関数のプロトタイプのメソッド　→　他のプロトタイプへ、、、
// 最終的にはundefinedが返ってくる
bob.hello();
`````

###2.hasOwnProperty と in

####hasOwnProperty とは
自分自身のオブジェクトのプロパティとして引数で与えた名前が存在するかどうかを確かめることができる

````js
function Person(name, age) {
    this.name = name;
    this.age = age;
}

Object.prototype.hello = function() {
    console.log('Object: hello ' + this.name);
}

const bob = new Person('Bob', 18);
// bobにnameプロパティが存在するかどうか引数に入れて確認
const result = bob.hasOwnProperty("age");
// trueと返ってくる
console.log(result);
// Objectのhelloメソッドを入れると
const result2 = bob.hasOwnProperty("hello");
// falseで返ってくる(あくまで自分自身のプロパティに対応)
console.log(result2);
`````

#### in とは

````js
function Person(name, age) {
    this.name = name;
    this.age = age;
}

Object.prototype.hello = function() {
    console.log('Object: hello ' + this.name);
}

const bob = new Person('Bob', 18);
const result = bob.hasOwnProperty("age");
console.log(result);
// bobオブジェクトの中に"引数"に対応するプロパティはあるか確認できる
console.log("name" in bob);
// この場合プロトタイプチェーンも遡るので、trueと返ってくる
console.log("hello" in bob);
// もちろん存在しないものはfalse
console.log("bye" in bob);
// Objectのプロトタイプに格納されているhasOwnPropertyもプロトタイプチェーンによって格納されているのでtrue
console.log("hasOwnProperty" in bob);
``````

* hasOwnPropertyは自分自身のプロパティのみ
* inはプロトタイプチェーンまで探す


今日はここまで！

#参考にさせて頂いた記事

* [【JS】ガチで学びたい人のためのJavaScriptメカニズム](https://www.udemy.com/course/javascript-essence/)