ページ

2012年7月9日

変数の存在とプロトタイプ: Javascriptを本格的に勉強し始めて驚かされたこと その2

nyuhuhuu cc
Javascript (JS) の勉強会に行ってきました。今週で4週目(第4回)です。第2回のときもそうでしたが、今回も驚きや新しい発見があったのでブログにまとめておこうと思います。テキストは引き続きこれを使っています。


パーフェクトJavaScript (PERFECT SERIES 4)

1. 変数の存在チェック(ReferenceError例外の発生を修正する)

宣言していない変数から値を取り出そうとするとReferenceError例外が起きる。この例外を回避する方法を挙げていく。
// 遅延評価を利用する
var a = a || 7; // aが既に値を持っていれば変数aの値を使う(イディオム)

// aが厳密にundefiendかどうか調べる その1
var a; // 既に定義されている場合は値はそのまま変わらない
var b = a !== undefined ? a : 7; // aが既に値を持っていれば変数aの値を使う

// aが厳密にundefiendかどうか調べる その2
if (typeof a !== 'undefined') {
  var b = a;
} else {
  var b = 7;
}

// aが宣言済みか(存在するか)を調べる
if ('a' in this) {
  var b = a;
} else {
  var b = 7;
}

2. new式の挙動

コンストラクタは以下のように書く。
function MyClass(x, y) {
  this.x = x;
  this.y = y;
}

これをnewしてオブジェクト(インスタンス)を生成する。このときのnew式の動作は以下のようになる。
  • 空のオブジェクト{}を生成する
  • new式で指定した関数(コンストラクタ)を呼び出す
  • this参照がオブジェクトのプロパティとなる
この挙動はあたかもクラス定義からインスタンスを生成しているように見えるが、Javascriptにはクラスという概念はない。ただ、コンストラクタ(関数)からnew式によりオブジェクトを生成しているだけである。ただ、Javaなどのクラスベースの言語を使っている人からすると、クラスを定義してインスタンスを生成していると考えた方が分かりやすいかもしれない。

3. フィールドとメソッドを持つクラス定義

Javascriptにはクラスはないけれど、コンストラクタ(関数)によりフィールドとメソッドを持つクラスのようなものを定義できる。
// クラス定義に相当
function MyClass(x, y) {
  // フィールドに相当
  this.x = x;
  this.y = y;
  // メソッドに相当
  this.show = function() {
    print(this.x, this.y);
  }
}
js> var obj = new MyClass(3, 2);
js> obj.show(); // => 3 2
ただしこのコードには以下の問題がある。
  • このコンストラクタをnewして生成されるインスタンスにはすべて同じshowメソッドが定義されるため、メモリ効率と実行効率がよくない
  • プロパティ値のアクセス制御(privateやpublic)ができない
このうち前者は以下の方法で解決できる。

4. プロトタイプ継承

上のコードには共通するshowメソッドをすべてのインスタンスのプロパティにコピーしてしまうため効率が悪かった。これをプロトタイプ継承を使って書き換えると以下のようになる。
function MyClass(x, y) {
  this.x = x;
  this.y = y;
}
MyClass.prototype.show = function() {
  print(this.x, this.y);
}
js> var obj = new MyClass(3, 2);
js> obj.show(); // => 3 2
このとき生成したインスタンスオブジェクトobjはプロパティにshowを持たないが、prototypeオブジェクトのプロパティshowを継承している。

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

パーフェクトJavascriptの138ページにいろいろ説明があるけど、要約するとメソッド呼び出しの優先順位は
  1. オブジェクト自身のプロパティ
  2. コンストラクタのprototypeオブジェクトのプロパティ
  3. さらにprototypeをたどって得たプロパティ
という風になり、最終的にObjectの持つプロパティが実行される(Objectも持たないプロパティの場合はundefinedになる)


Related Posts Plugin for WordPress, Blogger...