プロトタイプとは
実はJavaScriptの関数オブジェクトは、標準でprototypeプロパティを持っています。
試しに関数を作ってみます。
オブジェクトの中に何も記述しておりませんが、コンソールはしっかり表示されます。
function F() { }
console.log(F.prototype)
デフォルトでは空のオブジェクトを参照しています。
この関数F()のprototypeプロパティがが参照しているオブジェクトをプロトタイプオブジェクトといいます。
ではこのプロトタイプオブジェクトにpropというプロパティを作り、そこに値を入れてみましょう
//プロトタイプオブジェクトのプロパティ
F.prototype.prop = "プロトタイプ"
//インスタンス化
let obj = new F();
//propはobjオブジェクトのプロパティではないがそのように使える
console.log(obj.prop)
prototypeオブジェクトのプロパティはコンストラクタによって生成されたインスタンスから、あたかもそのインスタンスのプロパティであるかのように参照できます。
※あくまで参照しているだけなので、
obj.prop = "代入"
代入はできないです。
プロトタイプを使用するのメリット
//コンストラクタ
function User(email,name) {
this.email = email
this.name = name
}
//プロトタイプ
User.prototype.login = function () {
this.online = true
console.log(this.email , 'has logged in')
}
//インスタンス化
let japanese = new User("japan@gmail.com", "まさき")
japanese.login();
//コンソール
japan@gmail.com has logged in
プロトタイプを使って、login()メソッドを作りました。
でもこれは、オブジェクトの中にメソッド作れば同じじゃないか?と思うかもしれません
//コンストラクター
function User(email,name) {
this.email = email
this.name = name
this.online = true
this.login = function () {
console.log(this.email , 'has logged in')
}
}
//インスタンス化
let japanese = new User("japan@gmail.com", "まさき")
japanese.login();
//コンソール
japan@gmail.com has logged in
コンソール自体は同じになります。
何が違うのか
オブジェクトの中にプロパティ(メソッド)を書いてしまうとインスタンス化するごとに新しいプロパティが生成されます。
当然といえば当然なのですが、たくさんのインスタンスを生成するとその分メモリを消費します。
一方protptypeはプロトタイプオブジェクトを参照しているので、インスタンスを何個作ってもメモリは増えません。
クロージャー
余談ですが、ここでなぜ、プロトタイプオブジェクトでthisが使えるのだろうと思った方いるかもしれません。試しにコンソールでthisを見てみましょう。
//コンストラクタ
function User(email,name) {
this.email = email
this.name = name
}
//プロトタイプ
User.prototype.login = function () {
this.online = true
console.log(this)
}
//インスタンス化
let japanese = new User("japan@gmail.com", "まさき")
japanese.login();
//コンソール
User {email: 'japan@gmail.com', name: 'まさき', online: true}email: "japan@gmail.com"name: "まさき"online: true[[Prototype]]: Object
コンソールにUserが出てきましたね。プロトタイプオブジェクトの中でもthisはUserを表しています。
javaScriptでは「自分を定義した関数を親とする」のでプロトタイプオブジェクトの親は「User = this」になるわけです。
クロージャーについての記事