プロトタイプは、実体化済みのオブジェクト(インスタンス)です。
実体化済みであるオブジェクトをベースにして、新しいオブジェクトを生成できます。
とは、プロトタイプベースの対となる用語です。
静的な定義(未実体)であるクラスをベースにして、新しいオブジェクトを作成できます。
演算子を使って、コンストラクタ関数を、
インスタンス化(実体化)する事ができます。
実体化すると、新しいオブジェクトを作成する事ができます。
// MyFunc という名前の関数を宣言する
function MyFunc (){
}
// コンストラクタ関数を実体化し、新しいオブジェクトを作成する
var obj = new MyFunc();
console.log(obj);
// MyFunc という名前の関数を宣言する
function MyFunc (){
}
// 関数が所有する、デフォルトのプロトタイプオブジェクトを取得する
var prototype_obj = MyFunc.prototype;
console.log(prototype_obj);
// Array コンストラクタが所有する、デフォルトのプロトタイプオブジェクトを取得する
var prototype_obj0 = Array.prototype;
// Array オブジェクトを作成する
var array_obj = new Array();
// プロトタイプ(原型)となるオブジェクトを取得する
var prototype_obj1 = Object.getPrototypeOf(array_obj);
// 同一であるか確認する
console.log(prototype_obj0 === prototype_obj1); // true
プロトタイプは、静的な定義(未実体)ではありません。
プロトタイプは、オブジェクトであり、実体化済みのインスタンスです。
1つのプロトタイプは、複数のインスタンスから参照されます。
プロトタイプは、すべての派生オブジェクト間で共有されます。プロトタイプは、Live な資産です。
もしプロトタイプ内を変更した場合、すべての派生オブジェクトに影響があります。
// MyFunc という名前の関数を宣言する
function MyFunc (){
}
// デフォルトのプロトタイプオブジェクトを取得する
var prototype_obj = MyFunc.prototype;
// コンストラクタ関数を実体化し、新しいオブジェクトを作成する
var obj0 = new MyFunc();
var obj1 = new MyFunc();
var obj2 = new MyFunc();
// プロトタイプ(原型)となるオブジェクトを取得する
var prototype_obj0 = Object.getPrototypeOf(obj0);
var prototype_obj1 = Object.getPrototypeOf(obj1);
var prototype_obj2 = Object.getPrototypeOf(obj2);
// 同一であるか確認する
console.log(prototype_obj === prototype_obj0); // true
console.log(prototype_obj === prototype_obj1);
console.log(prototype_obj === prototype_obj2); // true
実体化後に変更しても、生成済みのインスタンスには、反映されません。
// MyFunc という名前の関数を宣言する
function MyFunc (){
}
// プロトタイプ用のオブジェクトを作成する
var prototype_obj = new Object();
prototype_obj.aaa = "a";
prototype_obj.bbb = "b";
prototype_obj.ccc = "c";
// ------------------------------------------------------------
// ------------------------------------------------------------
MyFunc.prototype = prototype_obj;
// コンストラクタ関数を実体化する
var obj = new MyFunc();
console.log(obj.aaa); // "a"
console.log(obj.bbb);
console.log(obj.ccc); // "c"
// MyFunc という名前の関数を宣言する
function MyFunc (){
}
// デフォルトのプロトタイプオブジェクトにデータを追加する
var prototype_obj = MyFunc.prototype;
prototype_obj.aaa = "a";
prototype_obj.bbb = "b";
prototype_obj.ccc = "c";
// MyFunc オブジェクトを作成する
var obj = new MyFunc();
console.log(obj.aaa); // "a"
console.log(obj.bbb);
console.log(obj.ccc); // "c"
プロトタイプを使って、オブジェクトを数珠つなぎのように連結する事ができます。
このような連結構造を、
プロトタイプチェーンといいます。
// MyFunc_A という名前の関数を宣言する
function MyFunc_A (){
}
// MyFunc_B という名前の関数を宣言する
function MyFunc_B (){
}
// MyFunc_C という名前の関数を宣言する
function MyFunc_C (){
}
// MyFunc_A オブジェクトを作成する(Object → MyFunc_A)
var obj_a = new MyFunc_A();
// MyFunc_B 関数を実体化した時に、インスタンスのプロトタイプとなるオブジェクトを指定する
MyFunc_B.prototype = obj_a;
// MyFunc_B オブジェクトを作成する(Object → MyFunc_A → MyFunc_B)
var obj_b = new MyFunc_B();
// MyFunc_C 関数を実体化した時に、インスタンスのプロトタイプとなるオブジェクトを指定する
MyFunc_C.prototype = obj_b;
// MyFunc_C オブジェクトを作成する(Object → MyFunc_A → MyFunc_B → MyFunc_C)
var obj_c = new MyFunc_C();
オブジェクトにプロパティが存在する場合、
オブジェクトからデータを取得します。存在しなかった場合、
次に、プロトタイプにアクセスします。プロトタイプにプロパティが存在する場合、
プロトタイプからデータを取得します。存在しなかった場合、さらに次のプロトタイプにアクセスします。
// MyFunc という名前の関数を宣言する
function MyFunc (){
this.bbb = "b";
}
// デフォルトのプロトタイプオブジェクトを取得する
var prototype_obj = MyFunc.prototype;
prototype_obj.aaa = "a";
// MyFunc オブジェクトを作成する
var obj = new MyFunc();
// 読み取りアクセステスト
console.log(obj.aaa);
console.log(obj.bbb);
console.log(obj.ccc);
// MyFunc_A という名前の関数を宣言する
function MyFunc_A (){
this.aaa = "a";
}
// MyFunc_B という名前の関数を宣言する
function MyFunc_B (){
this.bbb = "b";
}
// MyFunc_B 関数を実体化した時に、インスタンスのプロトタイプとなるオブジェクトを指定する
MyFunc_B.prototype = new MyFunc_A();
// MyFunc_B オブジェクトを作成する(Object → MyFunc_A → MyFunc_B)
var obj_b = new MyFunc_B();
// 読み取りアクセステスト
console.log(obj_b.aaa);
console.log(obj_b.bbb);
console.log(obj_b.ccc);
プロパティが存在しなかった場合、
自身のオブジェクトにプロパティが追加されます。
存在する場合、
自身のプロパティにデータがセットされます。
書き込みアクセスによって変化するのは、自身のオブジェクトのみです。
プロトタイプ内が、汚染する事はありません。
// MyFunc という名前の関数を宣言する
function MyFunc (){
}
// デフォルトのプロトタイプオブジェクトを取得する
var prototype_obj = MyFunc.prototype;
prototype_obj.aaa = "a";
prototype_obj.bbb = "b";
// MyFunc オブジェクトを作成する(Object → MyFunc)
var obj0 = new MyFunc();
var obj1 = new MyFunc();
// 書き込みアクセステスト
obj0.aaa = "書き込みA";
obj1.bbb = "書き込みB";
// 出力テスト(プロトタイプオブジェクト内は変化しない)
console.log(prototype_obj.aaa);
console.log(prototype_obj.bbb);
// ------------------------------------------------------------
// ------------------------------------------------------------
console.log(obj0.aaa);
console.log(obj1.aaa);
console.log(obj0.bbb);
console.log(obj1.bbb);
// MyFunc_A という名前の関数を宣言する
function MyFunc_A (){
this.aaa = "a";
this.bbb = "b";
}
// MyFunc_B という名前の関数を宣言する
function MyFunc_B (){
}
// MyFunc_A オブジェクトを作成する(Object → MyFunc_A)
var obj_a = new MyFunc_A();
// MyFunc_B 関数を実体化した時に、インスタンスのプロトタイプとなるオブジェクトを指定する
MyFunc_B.prototype = obj_a;
// MyFunc_B オブジェクトを作成する(Object → MyFunc_A → MyFunc_B)
var obj_b0 = new MyFunc_B();
var obj_b1 = new MyFunc_B();
// 書き込みアクセステスト
obj_b0.aaa = "書き込みA";
obj_b1.bbb = "書き込みB";
// 出力テスト(プロトタイプオブジェクト内は変化しない)
console.log(obj_a.aaa);
console.log(obj_a.bbb);
// ------------------------------------------------------------
// ------------------------------------------------------------
console.log(obj_b0.aaa);
console.log(obj_b1.aaa);
console.log(obj_b0.bbb);
console.log(obj_b1.bbb);
読み取りアクセス順は、プロパティと同じです。
プロトタイプが保有している関数オブジェクトにも、アクセスできます。
// MyFunc_A という名前の関数を宣言する
function MyFunc_A (){
// プライベートな変数
var _local_a = "a";
// ------------------------------------------------------------
// ------------------------------------------------------------
this.getA = function (){
return _local_a;
};
// Aにデータをセットするメソッド
this.setA = function (v){
_local_a = v;
};
}
// MyFunc_B という名前の関数を宣言する
function MyFunc_B (){
// プライベートな変数
var _local_b = "b";
// ------------------------------------------------------------
// ------------------------------------------------------------
this.getB = function (){
return _local_b;
};
// Bにデータをセットするメソッド
this.setB = function (v){
_local_b = v;
};
}
// MyFunc_A オブジェクトを作成する(Object → MyFunc_A)
var obj_a = new MyFunc_A();
// MyFunc_B 関数を実体化した時に、インスタンスのプロトタイプとなるオブジェクトを指定する
MyFunc_B.prototype = obj_a;
// MyFunc_B オブジェクトを作成する(Object → MyFunc_A → MyFunc_B)
var obj_b0 = new MyFunc_B();
var obj_b1 = new MyFunc_B();
// 出力テスト
console.log(obj_a.getA());
console.log(obj_b0.getA());
console.log(obj_b1.getA());
console.log(obj_b0.getB());
console.log(obj_b1.getB());
// ------------------------------------------------------------
// ------------------------------------------------------------
obj_b0.setA("書き込みA");
obj_b1.setB("書き込みB");
// 出力テスト(プロトタイプから供給しているメソッドを実行すれば、プロトタイプ内を変化させる事ができる)
console.log(obj_a.getA());
console.log(obj_b0.getA());
console.log(obj_b1.getA());
// ------------------------------------------------------------
// ------------------------------------------------------------
console.log(obj_b0.getB());
console.log(obj_b1.getB());
プロトタイプに1つの機能を追加すれば、すべての派生オブジェクトから利用できます。
しかし、
パブリックなメソッドは、プロトタイプ内が汚染する可能性があります。プロトタイプ内が汚染しないように、注意して実装する必要があります。
クロージャに書き込みアクセスしないようにします。
プロトタイプ内で必要な変数は、すべてプロパティとして公開します。
外部からアクセスを禁止したいプロパティは、命名を工夫します。
先頭や後尾にアンダーバーを付けて、怪しげな名前にするなどの方法があります。
// MyFunc という名前の関数を宣言する
function MyFunc (){
}
// MyFunc のデフォルトのプロトタイプオブジェクトを拡張する
(function(){
// ------------------------------------------------------------
// ------------------------------------------------------------
var self = MyFunc.prototype;
// ローカルで使用する変数(プロパティとして公開)
self._data = "初期値";
// ------------------------------------------------------------
// ------------------------------------------------------------
self.getData = function (){
return this._data;
};
// データをセットするメソッド
self.setData = function (v){
this._data = v;
//self._data = v;
};
})();
// MyFunc オブジェクトを作成する(Object → MyFunc)
var obj0 = new MyFunc();
var obj1 = new MyFunc();
// 出力テスト
console.log(obj0.getData());
console.log(obj1.getData());
// ------------------------------------------------------------
// ------------------------------------------------------------
obj0.setData("書き込み");
// 出力テスト
console.log(obj0.getData());
console.log(obj1.getData());
// MyFunc_A という名前の関数を宣言する
function MyFunc_A (){
// 自身のオブジェクト
var self = this;
// ------------------------------------------------------------
// ------------------------------------------------------------
self._local_a = "a";
// Aからデータを取得するメソッド
self.getA = function (){
return this._local_a;
};
// Aにデータをセットするメソッド
self.setA = function (v){
this._local_a = v;
};
}
// MyFunc_B という名前の関数を宣言する
function MyFunc_B (){
// 自身のオブジェクト
var self = this;
// ------------------------------------------------------------
// ------------------------------------------------------------
self._local_b = "b";
// Bからデータを取得するメソッド
self.getB = function (){
return this._local_b;
};
// Bにデータをセットするメソッド
self.setB = function (v){
this._local_b = v;
};
}
// MyFunc という名前の関数を宣言する
function MyFunc (){
}
// MyFunc_B 関数を実体化した時に、インスタンスのプロトタイプとなるオブジェクトを指定する
MyFunc_B.prototype = new MyFunc_A();
// MyFunc 関数を実体化した時に、インスタンスのプロトタイプとなるオブジェクトを指定する
MyFunc.prototype = new MyFunc_B();
// MyFunc オブジェクトを作成する(Object → MyFunc_A → MyFunc_B → MyFunc)
var obj0 = new MyFunc();
var obj1 = new MyFunc();
// 出力テスト
console.log(obj0.getA());
console.log(obj1.getA());
console.log(obj0.getB());
console.log(obj1.getB());
// ------------------------------------------------------------
// ------------------------------------------------------------
obj0.setA("書き込みA");
obj1.setB("書き込みB");
// 出力テスト
console.log(obj0.getA());
console.log(obj1.getA());
console.log(obj0.getB());
console.log(obj1.getB());
この方法は、インスタンスごとにメソッドが用意されるため、合理的ではありません。
そのかわり、カプセル化が実現できます。
// プロトタイプを指定して新しいオブジェクトを生成する関数
function ObjectCreateByPrototype(prototype){
var f = function (){};
f.prototype = prototype;
return new f();
}
引数に、関数の
prototypeプロパティにあるプロトタイプオブジェクトを指定します。
すると、
コンストラクタ関数を実行すること無く、オブジェクトを作成する事ができます。
// プロトタイプを指定して新しいオブジェクトを生成する関数
function ObjectCreateByPrototype(prototype){
var f = function (){};
f.prototype = prototype;
return new f();
}
// MyFunc という名前の関数を宣言する
function MyFunc (){
console.log("コンストラクタ関数が実行された");
}
// コンストラクタ関数を実行せずに、MyFunc オブジェクトを作成する
var obj = ObjectCreateByPrototype(MyFunc.prototype);
// 出力テスト
console.log(obj instanceof MyFunc);
console.log(obj instanceof Object); // true
プロトタイプオブジェクトは、ダミーです。変更される事はありません。
すべての初期化処理は、新しく生成されるオブジェクトに施されます。
// プロトタイプを指定して新しいオブジェクトを生成する関数
function ObjectCreateByPrototype(prototype){
var f = function (){};
f.prototype = prototype;
return new f();
}
// MyFunc_A コンストラクタ関数
function MyFunc_A (){
}
// MyFunc_B コンストラクタ関数
function MyFunc_B (){
MyFunc_A.apply(this,arguments);
}
// MyFunc_C コンストラクタ関数
function MyFunc_C (){
MyFunc_B.apply(this,arguments);
}
// MyFunc_B 関数を実体化した時に、インスタンスのプロトタイプとなるオブジェクトを指定する
MyFunc_B.prototype = ObjectCreateByPrototype(MyFunc_A.prototype);
// MyFunc_C 関数を実体化した時に、インスタンスのプロトタイプとなるオブジェクトを指定する
MyFunc_C.prototype = ObjectCreateByPrototype(MyFunc_B.prototype);
// MyFunc_A オブジェクトを作成する(Object → MyFunc_A)
var obj_a = new MyFunc_A();
// MyFunc_B オブジェクトを作成する(Object → MyFunc_A → MyFunc_B)
var obj_b = new MyFunc_B();
// MyFunc_C オブジェクトを作成する(Object → MyFunc_A → MyFunc_B → MyFunc_C)
var obj_c = new MyFunc_C();
// 出力テスト
console.log(obj_a instanceof Object); // true
console.log(obj_a instanceof MyFunc_A);
console.log(obj_a instanceof MyFunc_B);
console.log(obj_a instanceof MyFunc_C);
console.log(obj_b instanceof Object); // true
console.log(obj_b instanceof MyFunc_A);
console.log(obj_b instanceof MyFunc_B);
console.log(obj_b instanceof MyFunc_C);
console.log(obj_c instanceof Object); // true
console.log(obj_c instanceof MyFunc_A);
console.log(obj_c instanceof MyFunc_B);
console.log(obj_c instanceof MyFunc_C);
// プロトタイプを指定して新しいオブジェクトを生成する関数
function ObjectCreateByPrototype(prototype){
var f = function (){};
f.prototype = prototype;
return new f();
}
// MyFunc_A という名前の関数を宣言する
function MyFunc_A (){
// プライベートな変数
var _local_a = "a";
// ------------------------------------------------------------
// ------------------------------------------------------------
this.getA = function (){
return _local_a;
};
// Aにデータをセットするメソッド
this.setA = function (v){
_local_a = v;
};
}
// MyFunc_B という名前の関数を宣言する
function MyFunc_B (){
// 派生元コンストラクタ関数を実行する
MyFunc_A.apply(this,arguments);
// プライベートな変数
var _local_b = "b";
// ------------------------------------------------------------
// ------------------------------------------------------------
this.getB = function (){
return _local_b;
};
// Bにデータをセットするメソッド
this.setB = function (v){
_local_b = v;
};
}
// MyFunc_B 関数を実体化した時に、インスタンスのプロトタイプとなるオブジェクトを指定する
MyFunc_B.prototype = ObjectCreateByPrototype(MyFunc_A.prototype);
// MyFunc_B オブジェクトを作成する(Object → MyFunc_A → MyFunc_B)
var obj0 = new MyFunc_B();
var obj1 = new MyFunc_B();
// 出力テスト
console.log(obj0.getA());
console.log(obj1.getA());
console.log(obj0.getB());
console.log(obj1.getB());
// ------------------------------------------------------------
// ------------------------------------------------------------
obj0.setA("書き込みA");
obj1.setB("書き込みB");
// 出力テスト
console.log(obj0.getA());
console.log(obj1.getA());
console.log(obj0.getB());
console.log(obj1.getB());