No.1 プロトタイプとdelete演算子
ここからは、応用編です。
コンストラクタ
プロトタイプを学ぶ前に少しコンストラクタに関しておさらいしておきましょう。詳細に関しては関数 No.4 コンストラクタを参照しましょう。
まずコンストラクタは次のような形で記述しましたね
1 2 3 4 5 6 7 8 9 10 11 12 | var Car = function(name) { this.name = name; this.drive = function() { console.log("Let's go " + this.name + "!"); }; }; var mycar = new Car('Bobbie'); mycar.drive(); // Let's go Bobbie! var sharecar = new Car('Sam'); sharecar.drive(); // Let's go Sam! |
ここではCarオブジェクトを生成するためのコンストラクタに無名関数を利用しています。 new演算子を利用して新たなインスタンスを作成します。 コンストラクタの引数に渡した文字列がnameに格納され、driveメソッドで表示されます。
このことから、イメージとして色々な文字列を引数に渡すことでオブジェクトのテンプレートとしてコンストラクタを利用できるというものでしたね。
便利ですね。・・・なんて思いませんでした?
実はこれにはちょっとした問題があるのです。そして、問題の対処法こそが今回のプロトタイプなのです。
プロトタイプ
先ほどのコンストラクタの場合、new演算子で新たにインスタンスが作成される度にdriveというメソッドが生成されています。 何個このインスタンスを生成しても、driveメソッドはメッセージを表示する時にnameプロパティを参照して表示するだけです。 そのため、インスタンスが生成される度、driveメソッドが生成されるのは効率的であるとは言えません。
そこで利用できるのがprototypeという特別なプロパティです。
1 2 3 4 5 6 7 8 9 10 11 12 13 | var Car = function(name) { this.name = name; }; Car.prototype.drive = function(){ console.log("Let's go " + this.name + "!"); } var mycar = new Car('Bobbie'); mycar.drive(); // Let's go Bobbie! var sharecar = new Car('Sam'); sharecar.drive(); // Let's go Sam! |
先ほどと動作は変わりませんが、driveメソッドとして定義されている関数オブジェクトは1カ所です。 new演算子によって生成されたオブジェクトは元となった関数オブジェクトのprototypeへの参照を持つようになります。 そして、そのオブジェクトに設定されていないプロパティ/メソッドを参照した時には、prototypeを参照して評価されます。 つまり、mycarもsharecarも同じ関数オブジェクトを利用しています。
これで複数個のインスタンスを生成する場合でもメモリの節約ができますね。
プロトタイプを利用して・・・
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | var Detail = function() { this.type = 'Classic'; } var Action = function() { this.drive = function() { console.log("Let's go " + this.name + "!"); } } var Car = function(name) { this.name = name; } Action.prototype = new Detail(); Car.prototype = new Action(); var mycar = new Car('Bobbie'); mycar.drive(); // Let's go Bobbie! console.log(mycar.type); // 'Classic' |
このようにプロトタイプに設定した値を次々と参照していく形をプロトタイプチェーンと呼びます。
delete演算子
delete演算子は、オブジェクトのプロパティの削除に利用できます。
1 2 3 4 5 6 | var o = { key : 'value' }; console.log(o.key); // 'value' delete o.key; console.log(o.key); // undefined |
一見すると何でも削除できそうですが、次の場合は削除することができません。
1 2 3 | var x = 10; delete x; console.log(x); // 10 |
これは、一度削除されて再設定されているわけではなく、削除自体されていません。
1 | delete x; // false |
この原因は変数xがグローバルオブジェクトのプロパティだからです。
また、特徴的な削除のされ方があります。それはprototypeで宣言した名前のプロパティを削除しようとした場合です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | var Car = function(name) { this.name = name; }; Car.prototype.drive = function() { console.log("Let's go " + this.name + "!"); } Car.prototype.type = 'Classic'; var mycar = new Car(); console.log(mycar.type); //'Classic' mycar.type = 'Modern'; console.log(mycar.type); //'Modern' delete mycar.type; console.log(mycar.type); //'Classic' |
ポイントは最後のdelete演算子を利用した後の部分です。 mycar.typeを削除したので、一見undefinedが出力されそうですが、結果は’Classic’が表示されます。 理由は、ここで削除されているのは14行目で宣言されたmycar自身のtypeであり、Car.prototype.typeは削除されていないからです。 delete演算子は、対象となるオブジェクト自身が持つプロパティでないと削除できないのです。
今回はここまで。 次回は、クロージャーについてやります。 どうぞ、お楽しみに!!!