0
0

More than 1 year has passed since last update.

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

Posted at

はじめに

Udemyの【JS】ガチで学びたい人のためのJavaScriptメカニズムの講座の振り返りです。

前回の記事

目的

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

本題

1.プロトタイプチェーン

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

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

例1

前提として

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

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

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の方をコメントアウトすると

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が関数内にあった場合

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 とは

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

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 とは

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はプロトタイプチェーンまで探す

今日はここまで!

参考にさせて頂いた記事

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0