JavaScriptのprototypeについて
JavaやC#と比べてJavaScriptという言語はクラスがないという点で大きく違います。構文はC言語ライクで似ているのですが、オブジェクト指向でサポートされているものが違い、JavaやC#ではクラスベースのオブジェクト指向、JavaScriptはプロトタイプベースのオブジェクト指向です。
JavaScriptにはクラスやインターフェイスはありません。オブジェクトの実装や、型の継承はプロトタイプというのを使用して実装されます。
プロトタイプを使えばクラスと同じような機能を実装できますが、書き方が少々複雑で、プロトタイプを使用して型の継承を実装しているコードはあまり見ないです。
元々、JavaScriptは動的型付け言語で、メソッドやプロパティを自由に拡張できるので、プロトタイプを使用する必要はあまりないです。
ただし、オブジェクトを拡張したいという場合プロトタイプを使用すると非常に簡単に実装できます。
prototypeを使用してメソッド追加
例えばArrayのインスタンスにisEmpty()というメソッドを追加する場合は以下のように実装します。
isEmpty()は配列が空の場合trueを返し、空でない場合falseを返します。
//isEmpty()の実装 Array.prototype.isEmpty = function(){ return this.length == 0; };
Array.prototypeにisEmptyというメソッドを追加しています。
関数の中で使われているthisは、Arrayのインスタンスを指しています。なのでthis.lengthは配列の長さということになります。
このように「オブジェクト.prototype.メソッド名 = 関数」という書き方でオブジェクトを拡張できます。
実際に使ってみましょう。
Array.prototype.isEmpty = function(){ return this.length == 0; }; var xs = []; var ys = [1,2,3]; console.log( xs.isEmpty());//true console.log( ys.isEmpty());//false
prototypeを使用しなくとも関数を宣言すれば同じ処理はできます。
var isEmpty = function(array){ return array.length == 0; }; var xs = []; var ys = [1,2,3]; console.log(isEmpty(xs));//true console.log(isEmpty(ys));//false
関数呼び出しはisEmpty(xs)という形ですが、プロトタイプを使用した場合はxs.isEmpty(xs)という形で呼び出します。
細かな実行の違いはありますが、基本的な動作は同じです。
関数かプロトタイプでの拡張かの実装方法を場面に合わせて適切なものを選択しましょう。
n回繰り返すtimes()を実装
Arrayと同様にNumberも拡張可能です。
n回繰り返す
Number.prototype.times = function(f){ for(var i=0;i<this;i++){ f(i); } };
thisは数値になります。
実行してみましょう。
Number.prototype.times = function(f){ for(var i=0;i<this;i++){ f(i); } }; var xs = []; (10).times(function(i){ xs.push(i); }); console.log(xs); // [0,1,2,3,4,5,6,7,8,9]
times()の引数に入れた関数を10回実行しています。
times()を呼び出す場合は数値を()で囲まないといけません。
囲まずに「10.times(****)」と実行すると、「.」が小数点と間違えて解釈されてエラーになります。
どのような動きになっているのかわかりづらいので、プロトタイプを使わずに、コードを分解してみましょう。
var times = function(count,f){ for(var i=0;i<count;i++){ f(i); } }; var xs = []; var g = function(i){ xs.push(i); }; times(10,g); console.log(xs);
さらに分解。
var xs = []; var count = 10; for(var i=0;i<count;i++){ xs.push(i); } console.log(xs);
xs.push()を10回繰り返して呼び出しているのがわかります。
配列をシャッフルするshuffle()を実装
配列の要素ををシャッフルして新しい配列を返すshuffle()を実装。
画像をランダムに表示する場合などに便利です。
Array.prototype.shuffle = function () { var xs = this.concat(); for (var i = 0; i < xs.length; i++) { var j = xs.length * Math.random() | 0; var xi = xs[i]; xs[i] = xs[j]; xs[j] = xi; } return xs; };
実行してみましょう。
var xs = [1,2,3,4,5,6,7,8,9]; console.log(xs.shuffle()); //[4,2,1,8,5,7,9,0,3,6] console.log(xs.shuffle()); //[1,2,0,6,9,7,3,5,8,4] console.log(xs.shuffle()); //[5,8,6,4,2,7,1,9,3,0]
prototypeを使用する際の注意点
このようにprotoypeを使えばオブジェクトを拡張することが可能です。
ただし、ライブラリを併用したり、複数人で開発する場合は、prototypeで追加したメソッドの名前が競合してしまう場合があるので、注意が必要です。