JavaScript オブジェクト指向プログラミング (1): カプセル化
著者: Ruan Yifeng
JavaScript はオブジェクトベースの言語であり、遭遇するほとんどすべてがオブジェクトです。ただし、構文にクラスがないため、真のオブジェクト指向プログラミング (OOP) 言語ではありません。
では、「プロパティ」と「メソッド」をオブジェクトにカプセル化したい場合、あるいはプロトタイプオブジェクトからインスタンスオブジェクトを生成したい場合は、どうすればよいでしょうか?
1. オブジェクト生成の元のモード
猫を「名前」と「色」の 2 つの属性を持つオブジェクトとみなします。
var Cat = { name : '', color : '' }
次に、このプロトタイプ オブジェクトに基づいて 2 つのインスタンス オブジェクトを生成する必要があります。
var cat1 = {}; // 创建一个空对象 cat1.name = "大毛"; // 按照原型对象的属性赋值 cat1.color = "黄色"; var cat2 = {}; cat2.name = "二毛"; cat2.color = "黑色";
さて、これが最もシンプルなパッケージです。ただし、この書き方には 2 つの欠点があります。1 つは、より多くのインスタンスが生成される場合、作成が非常に面倒になることです。2 つ目は、インスタンスとプロトタイプ間の接続を確認する方法がありません。
2. オリジナルモードの改善
コードの重複の問題を解決する関数を書くことができます。
function Cat(name,color){ return { name:name, color:color } }
インスタンス オブジェクトの生成は、関数を呼び出すことと同じです:
var cat1 = Cat("大毛","黄色"); var cat2 = Cat("二毛","黑色");
このメソッドの問題は、依然として cat1 と cat2 の間に本質的な接続がなく、それらが同じプロトタイプ オブジェクトのインスタンスであることを反映できないことです。
3. コンストラクター パターン
プロトタイプ オブジェクトからインスタンスを生成する問題を解決するために、JavaScript はコンストラクター パターンを提供します。
いわゆる「コンストラクター」は実際には通常の関数ですが、this 変数は内部的に使用されます。コンストラクターで new 演算子を使用するとインスタンスが生成され、this 変数はインスタンス オブジェクトにバインドされます。
たとえば、cat のプロトタイプ オブジェクトは次のように記述できるようになり、
function Cat(name,color){ this.name=name; this.color=color; }
インスタンス オブジェクトを生成できるようになりました。
var cat1 = new Cat("大毛","黄色"); var cat2 = new Cat("二毛","黑色"); alert(cat1.name); // 大毛 alert(cat1.color); // 黄色
この時点で、cat1 と cat2 には、コンストラクターを指すコンストラクター属性が自動的に含まれます。
alert(cat1.constructor == Cat); //true alert(cat2.constructor == Cat); //true
Javascript は、プロトタイプ オブジェクトとインスタンス オブジェクトの間の関係を検証するための instanceof 演算子も提供します。
alert(cat1 instanceof Cat); //true alert(cat2 instanceof Cat); //true
4. コンストラクターパターンの問題点
コンストラクターメソッドは使いやすいですが、メモリを無駄に消費するという問題があります。
見てください。不変属性「type」(タイプ) を Cat オブジェクトに追加し、メソッド Eat (マウスを食べる) を追加します。すると、プロトタイプ オブジェクト Cat は次のようになります:
function Cat(name,color){ this.name = name; this.color = color; this.type = "猫科动物"; this.eat = function(){alert("吃老鼠");}; }
同じメソッドを使用してインスタンスを生成します:
var cat1 = new Cat("大毛","黄色"); var cat2 = new Cat ("二毛","黑色"); alert(cat1.type); // 猫科动物 cat1.eat(); // 吃老鼠
表面的には問題がないように見えますが、実際には、そうすることには大きな欠点があります。つまり、インスタンス オブジェクトごとに、type 属性と Eat() メソッドの内容はまったく同じになります。インスタンスが生成されるたびに、繰り返しの内容のためにより多くのメモリを占有する必要があります。これは環境に優しくも効率的でもありません。
Alert(cat1.eat == cat2.eat); //false
type 属性と Eat() メソッドをメモリ内で 1 回だけ生成し、その後はすべてのインスタンスがそのメモリ アドレスを指すようにすることはできますか?答えは「はい」です。
5. プロトタイプ モード
JavaScript では、各コンストラクターが別のオブジェクトを指すプロトタイプ属性を持つことを規定しています。このオブジェクトのすべてのプロパティとメソッドは、コンストラクターのインスタンスによって継承されます。
これは、これらの不変のプロパティとメソッドをプロトタイプ オブジェクトに直接定義できることを意味します。
function Cat(name,color){ this.name = name; this.color = color; } Cat.prototype.type = "猫科动物"; Cat.prototype.eat = function(){alert("吃老鼠")};
次に、インスタンスを生成します。
var cat1 = new Cat("大毛","黄色"); var cat2 = new Cat("二毛","黑色"); alert(cat1.type); // 猫科动物 cat1.eat(); // 吃老鼠
このとき、すべてのインスタンスの type 属性と Eat() メソッドは実際には同じメモリ アドレスとなり、プロトタイプ オブジェクトを指すため、動作効率が向上します。
Alert(cat1.eat == cat2.eat); //true
6. プロトタイプモード検証メソッド
6.1 isPrototypeOf()
このメソッドは、特定のプロトタイプオブジェクトとインスタンスの間の関係を決定するために使用されます。
alert(Cat.prototype.isPrototypeOf(cat1)); //true alert(Cat.prototype.isPrototypeOf(cat2)); //true
6.2 hasOwnProperty()
各インスタンス オブジェクトには hasOwnProperty() メソッドがあり、特定のプロパティがローカル プロパティであるか、プロトタイプ オブジェクトから継承されたプロパティであるかを判断するために使用されます。
alert(cat1.hasOwnProperty("name")); // true alert(cat1.hasOwnProperty("type")); // false
6.3 in 演算子
in 演算子は、インスタンスに特定の属性が含まれているかどうか、それがローカル属性であるかどうかを判断するために使用できます。
alert("name" in cat1); // true alert("type" in cat1); // true
in 演算子を使用して、オブジェクトのすべてのプロパティを走査することもできます。
for(var prop in cat1) { alter("cat1["+prop+"]="+cat1[prop]) }
その他の Javascript オブジェクト指向プログラミング (1) カプセル化関連の記事は、 PHP中国語ネットに注目!