JavaScript はオブジェクトベースの言語であり、遭遇するほとんどすべてがオブジェクトです。ただし、構文にクラスがないため、真のオブジェクト指向プログラミング (OOP) 言語ではありません。
では、「プロパティ」と「メソッド」をオブジェクトにカプセル化したい場合、またはプロトタイプ オブジェクトからインスタンス オブジェクトを生成したい場合は、どうすればよいでしょうか?
1. オブジェクト生成のオリジナルモード
猫を「名前」と「色」という 2 つの属性を持つオブジェクトとして考えるとします。
var Cat = { name : '', color : '' }
次に、このプロトタイプ オブジェクトの仕様 (スキーマ) に基づいて 2 つのインスタンス オブジェクトを生成する必要があります。
var cat1 = {}; // 创建一个空对象 cat1.name = "大毛"; // 按照原型对象的属性赋值 cat1.color = "黄色"; var cat2 = {}; cat2.name = "二毛"; cat2.color = "黑色";
これは最も単純なカプセル化であり、2 つのプロパティを 1 つのオブジェクトにカプセル化します。ただし、この書き方には 2 つの欠点があります。1 つは、より多くのインスタンスが生成される場合、作成が非常に面倒になることです。2 つ目は、インスタンスとプロトタイプ間の接続を確認する方法がありません。
2. オリジナルモードの改善
コードの重複の問題を解決する関数を作成できます。
function Cat(name,color){ return { name:name, color:color } }
インスタンス オブジェクトの生成は、関数の呼び出しと同じです。
var cat1 = Cat("大毛","黄色"); var cat2 = Cat("二毛","黑色");
このメソッドの問題は依然として、cat1 と cat2 の間に本質的な接続がなく、それらが同じプロトタイプ オブジェクトのインスタンスであることを反映できないことです。
3. コンストラクターパターン
プロトタイプオブジェクトからインスタンスを生成する問題を解決するために、JavaScript はコンストラクター (Constructor) パターンを提供します。
いわゆる「コンストラクター」は実際には通常の関数ですが、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. プロトタイプモードの検証方法
プロトタイプ属性と連携するために、JavaScript はそれを使用するのに役立ついくつかの補助メソッドを定義します。 、
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 演算子を使用すると、インスタンスに特定の属性が含まれているかどうか、それがローカル属性であるかどうかを判断できます。
alert("name" in cat1); // true alert("type" in cat1); // true
in 演算子を使用して、オブジェクトのすべてのプロパティを調べることもできます。
for(var prop in cat1) { alert("cat1["+prop+"]="+cat1[prop]); }
上記はすべて JavaScript のカプセル化に関するもので、皆さんの学習に役立つことを願っています。