JSの基本的なことをちょっと
掘り下げてみる話シリーズ
Chapter04. ~ prototype編(やっと..!) ~
We Are JavaScripters! :)) 6th
@21cafe
聴衆ターゲット
JSはまだほとんどかいたことがない→×
JSをかいていて、動くんだけど

何でそうなるのかよくわかっていない→○
言語仕様を深く理解している方→×
ベースに

している本▷
オライリー

開眼!JavaScript
JS に慣れてきた人に
オススメの一冊!
とてもお世話になりました。m(__)m
http://qiita.com/howdy39/items/35729490b024ca295d6c
前回までの復習
(2ヶ月前でごめんなさい。。)
JavaScriptは
プロトタイプベースの

オブジェクト指向言語

である
引用:MDN

https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Details_of_the_Object_Model
クラスベースとプロトタイプベースの比較
引用:MDN

https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Details_of_the_Object_Model
前回話したところ
オブジェクトの生成方法

(コンストラクタ関数)

と、

JSに存在するオブジェクトの

全体像のお話をしました
コンストラクタ関数まとめ
普段使っているネイティブオブジェクトは
すべてコンストラクタ関数から生成されて
いる
new演算子を使わなければただの関数
new演算子を使うと、

1.thisにオブジェクト生成&returnを行う

2.prototype継承が行われる(※今回話すところ)
9つのネイティブオブジェクトのコンストラクタ
Number()
String()
Boolean()
Object()
Array()
Function()
Date()
RegExp()
Error()
※Math はコンストラクタではなく

 静的オブジェクト
プリミティブ値はオブジェクトではない

null, undefined, “文字列”, 10, true, falseは

オブジェクトではなくプリミティブ型。

ただし、nullとundefinedをのぞくプリミティブ値は、一時的
にオブジェクトに変換されオブジェクトのようにふるまう
オブジェクトという言葉において、

JavaScriptオブジェクトとObject()は別物

・Array()オブジェクト

・Object()オブジェクト
JSの世界はすべてオブジェクト?
詳細が気になる人はslideshareをチェック!
https://www.slideshare.net/YukikoTamiya/js-chapter03-
prototype
引用:MDN

https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Details_of_the_Object_Model
今回話すところ
??
INDEX
謎のオブジェクト__proto__
アクセスの仕組み

(プロトタイプチェーン)
prototypeはなぜ存在するのか?
謎のオブジェクト
__proto__
※var arr1 = Array()

 var arr1 = [];

 と同じ
__proto__
ってなんだ??
Array()
new Array()

インスタンス化
arr1
__proto__
length:0
謎のオブジェクト
?
__proto__の中身から探る
__proto__の中身から探る
MDNより
__proto__の中身から探る
MDNより
__proto__の中身から探る
MDNより
Array()
new Array()

インスタンス化
arr1
__proto__
length:0
Array.prototype
join()
push()
concat()
…
prototype
__proto__
Function()のインスタンスを生成する際に

自動的に付与するオブジェクト

※関数をコンストラクタとして使用するかどうかに関わ
らず、自動的に生成される
コンストラクタ関数でprototypeプロパティ
に定義したものと同値
※__proto__は非標準でしたが、ECMAScript 2015で初めて標準化されました。
オリジナルの
コンストラクタ関数で
挙動をCheck!
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
getName()
prototype
name
age
tami [オブジェクト]
アクセスの仕組み
(プロトタイプチェーン)
pushメソッドを呼んでみる
pushメソッドを呼んでみる
pushメソッドを呼んでみる
pushメソッドを呼んでみる
呼べた(そりゃそうか)
あれ、でも普段__proto__なんて使わない…
あれ、でも普段__proto__なんて使わない…
あれ、でも普段__proto__なんて使わない…
あれ、でも普段__proto__なんて使わない…
どうして呼べるの??
プロトタイプチェーン
①そのオブジェクトにプロパティがあるか調べる
プロトタイプチェーン
①そのオブジェクトにプロパティがあるか調べる
あった
そのプロパティ
を返す
プロトタイプチェーン
①そのオブジェクトにプロパティがあるか調べる
②__proto__をたどって

プロパティがあるか調べる
あった
そのプロパティ
を返す
ない
プロトタイプチェーン
①そのオブジェクトにプロパティがあるか調べる
②__proto__をたどって

プロパティがあるか調べる
あった
あった
そのプロパティ
を返す
ない
プロトタイプチェーン
①そのオブジェクトにプロパティがあるか調べる
②__proto__をたどって

プロパティがあるか調べる
あった
あった
そのプロパティ
を返す
ない
③さらに上の階層の__proto__
を見に行く(ループ)
プロトタイプチェーン
①そのオブジェクトにプロパティがあるか調べる
②__proto__をたどって

プロパティがあるか調べる
あった
あった
そのプロパティ
を返す
ない
③さらに上の階層の__proto__
を見に行く(ループ)
④nullになるまで行う

(終着点は必ずObject.prototype)
実際にプロパティを
探す動きを追ってみよう

(Personコンストラクタの例)
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
getName()
prototype
name
age
tami [オブジェクト]
実際にプロパティを
探す動きを追ってみよう
1.tami.name
2.tami.getName
3.tami.hogehoge
1. tami.name
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
getName()
prototype
name
age
tami [オブジェクト]
1. tami.name
❶tamiを探す
window
※windowオブジェクト
グローバルオブジェクトとも呼ばれる
JavaScriptによって裏で設定されている
Webブラウザ環境でJavaScriptのコードをかく
には、windowオブジェクト内で実行する必要
がある
※windowオブジェクト
グローバルオブジェクトとも呼ばれる
JavaScriptによって裏で設定されている
Webブラウザ環境でJavaScriptのコードをかく
には、windowオブジェクト内で実行する必要
がある
windowオブジェクト
グローバルオブジェクトとも呼ばれる
すべてのJavaScriptの実装環境は単一の

グローバルオブジェクトを持たなければならない
Webブラウザ環境でJavaScriptのコードをかくに
は、windowオブジェクト内で実行する必要がある
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
getName()
prototype
name
age
tami [オブジェクト]
1. tami.name
❶tamiを探す
window
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
getName()
prototype
name
age
tami [オブジェクト]
1. tami.name
❶tamiを探す
window
あった!
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
getName()
prototype
name
age
tami [オブジェクト]
1. tami.name
❷nameを探す
window
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
getName()
prototype
name
age
tami [オブジェクト]
1. tami.name
❷nameを探す
window
あった!
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
getName()
prototype
name
age
tami [オブジェクト]
1. tami.name
❷nameを探す
window
あった!
2. tami.getName
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
getName()
prototype
name
age
tami [オブジェクト]
2. tami.getName
❶tamiを探す
window
あった!
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
getName()
prototype
name
age
tami [オブジェクト]
❷getNameを探す
window
2. tami.getName
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
getName()
prototype
name
age
tami [オブジェクト]
❷getNameを探す
window
ない…
2. tami.getName
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
getName()
prototype
name
age
tami [オブジェクト]
❸__proto__を探す
window
2. tami.getName
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
getName()
prototype
name
age
tami [オブジェクト]
❸__proto__を探す
window
あった!
2. tami.getName
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
prototype
name
age
tami [オブジェクト]
❹getNameを探す
window
getName()
2. tami.getName
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
prototype
name
age
tami [オブジェクト]
❹getNameを探す
window
getName()
あった!
2. tami.getName
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
prototype
name
age
tami [オブジェクト]
❹getNameを探す
window
getName()
あった!
2. tami.getName
3. tami.hogehoge
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
getName()
prototype
name
age
tami [オブジェクト]
3. tami.hogehoge
❶tamiを探す
window
あった!
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
getName()
prototype
name
age
tami [オブジェクト]
❷hogehogeを探す
window
ない…
3. tami.hogehoge
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
getName()
prototype
name
age
tami [オブジェクト]
❸__proto__を探す
window
あった!
3. tami.hogehoge
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
prototype
name
age
tami [オブジェクト]
❹hogehogeを探す
window
getName()
3. tami.hogehoge
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
prototype
name
age
tami [オブジェクト]
❹hogehogeを探す
window
getName()
3. tami.hogehoge
ない…
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
prototype
name
age
tami [オブジェクト]
window
getName()
3. tami.hogehoge
__proto__
これなんの
__proto__?
❺tami.__proto__.__proto__を探す
tami.__proto__.__proto__
Object.prototypeのようだ
※__proto__の中の

 constructorプロパティについて
インスタンスを生成した

コンストラクタ関数を

参照することができます
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
prototype
name
age
tami [オブジェクト]
window
getName()
3. tami.hogehoge
__proto__
これなんの
__proto__?
❺tami.__proto__.__proto__を探す
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
prototype
name
age
tami [オブジェクト]
window
getName()
3. tami.hogehoge
__proto__
Object() [関数]
prototype
Object.prototype [オブジェクト]
❻hogehogeを探す
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
prototype
name
age
tami [オブジェクト]
window
getName()
3. tami.hogehoge
__proto__
Object() [関数]
prototype
Object.prototype [オブジェクト]
❻hogehogeを探す
ない…
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
prototype
name
age
tami [オブジェクト]
window
getName()
3. tami.hogehoge
__proto__
Object() [関数]
prototype
Object.prototype [オブジェクト]
❼__proto__を探す
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
prototype
name
age
tami [オブジェクト]
window
getName()
3. tami.hogehoge
__proto__
Object() [関数]
prototype
Object.prototype [オブジェクト]
❽nullを見つけて終了
__proto__:nullnull
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
prototype
name
age
tami [オブジェクト]
window
getName()
3. tami.hogehoge
__proto__
Object() [関数]
prototype
Object.prototype [オブジェクト]
❽nullを見つけて終了
__proto__:nullnull
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
prototype
name
age
tami [オブジェクト]
window
getName()
3. tami.hogehoge
__proto__
Object() [関数]
prototype
Object.prototype [オブジェクト]
❽nullを見つけて終了
__proto__:nullnull
プロトタイプチェーン
①そのオブジェクトにプロパティがあるか調べる
②__proto__をたどって

プロパティがあるか調べる
あった
あった
そのプロパティ
を返す
ない
③さらに上の階層の__proto__
を見に行く(ループ)
④nullになるまで行う

(終着点は必ずObject.prototype)
なぜこのような仕組みがあるのか?
なぜprototypeなのか?
プロトタイプによる継承を行うことにより、
同じメソッドを共有する、効率的なオブジェ
クトインスタンスを生成することができる

引用: 開眼JavaScript
なぜprototypeなのか?
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
prototype
name
age
tami01
getName()
getBirth()
なぜprototypeなのか?
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
prototype
name
age
tami01
getName()
tami02 tami03 tami04
getBirth()
なぜprototypeなのか?
Person() [関数]
new Person(“tami”,20)

インスタンス化
__proto__
getAge()
Person.prototype [オブジェクト]
prototype
name
age
tami01
getName()
tami02 tami03 tami04
getBirth()
Arrayを改めてながめてみる
Arrayを改めてながめてみる
Arrayを改めてながめてみる
Array()
new Array()

インスタンス化
myArray
__proto__
length:0
Array.prototype
join()
push()
concat()
…
prototype
isArray
Arrayを改めてながめてみる
Arrayを改めてながめてみる
Array()
new Array()

インスタンス化
myArray
__proto__
length:0
Array.prototype
join()
push()
concat()
…
prototype
isArray
Arrayを改めてながめてみる
Array()
new Array()

インスタンス化
myArray
__proto__
length:0
Array.prototype
join()
push()
concat()
…
prototype
isArray
prototypeまとめ
謎のオブジェクト__proto__は、

プロトタイプチェーンをたどるための

プロパティだった
ネイティブオブジェクトは

prototypeの仕組みを使ってメソッドにアク
セスしている
みなさんのJSライフの

理解の一助になれば幸いです!
ありがとうございました!

JSの基本的なことをちょっと掘り下げてみる話シリーズ Chapter04. 〜 prototype編(やっと..!) 〜