読者です 読者をやめる 読者になる 読者になる

うさがにっき

読書感想文とプログラムのこと書いてきます

prototypeを使ったオブジェクト指向

概要

JavaScript入門書を読んで気になった点 その3 - うさがにっき
の続き

JavaScriptにおけるオブジェクト指向

JavaScriptでは関数(Functionオブジェクト)にクラスとしての役割を与えている

var Member = function(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
  this.getName = function() {
    return this.lastName + " " + this.firstName;
  }
}

var mem = new Member("test", "result");
document.writeln(mem.getName());
動的にメソッドを追加できたりする

生成したinstanceに対してメソッドを追加した

var Member = function(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
}

var mem = new Member("test", "result");

mem.getName = function() {
  return this.lastName + " " + this.firstName;
}

document.writeln(mem.getName());

プロトタイプベースのオブジェクト指向

コンストラクタによるメソッドの追加はメソッドをコピーしているのでメモリの無駄があったりすると言われている
そこでプロトタイプベースのオブジェクト指向を使う

オブジェクトにメンバを追加するために、prototypeというプロパティがある
prototypeプロパティはデフォルトで空のオブジェクトを参照しているが、これにプロパティやメソッドを追加できる

オブジェクトをinstance化した場合、instanceは基となるオブジェクトに属するprototypeオブジェクトに対して、暗黙的な参照を持つことになる
つまり、prototypeオブジェクトはコピーされないのでメモリの節約になる

具体的なコードはこんな感じ

var Member = function(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
};

Member.prototype.getName = function() {
  return this.lastName + " " + this.firstName;
};

var mem = new Member("test", "result");
document.writeln(mem.getName());
プロトタイプオブジェクトを利用することのメリット
  • メモリの使用量を軽減できる

メソッドへの暗黙の参照をinstanceを持つため

  • メンバの追加や変更をinstanceがリアルタイムに認識できる

プロトタイプオブジェクトへの変更や削除を、instance側で動的に認識できる
つまりnewしてからそのprototypeへメソッドを追加できたりする

var Member = function(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
};

var mem = new Member("test", "result");

Member.prototype.getName = function() {
  return this.lastName + " " + this.firstName;
};

document.writeln(mem.getName());
prototypeオブジェクトのプロパティの設定
var Member = function(){};
Member.prototype.sex = "men";

var mem1 = new Member();
var mem2 = new Member();
document.writeln(mem1.sex + "|" + mem2.sex);
mem2.sex = "women";
document.writeln(mem1.sex + "|" + mem2.sex);

prototypeのプロパティはinstanceのプロパティに隠蔽されて見えなくなる
そのため、prototypeでプロパティを使っても意味がないので、

プロパティの宣言 コンストラクタ
メソッドの宣言 プロトタイプ

と扱うと良い

オブジェクトリテラルでprototypeを定義
var Member = function(firstName, lastName){
  this.firstName = firstName;
  this.lastName = lastName;
};

Member.prototype = {
  getName:function(){return this.lastName + " " + this.firstName;},
  toString:function(){return this.lastName + this.firstName;}
};

こんな感じでオブジェクトリテラルを使うと

  • 記述を最小限に抑えられる
  • オブジェクト名に変更があっても影響箇所を限定できる
  • 同一オブジェクトのメンバ定義が一つのブロックに収められているため、コードの可読性が上がる

・・・けどJavaになれてると個別にprototypeはドット演算子で宣言したくなる