JavaScript のオブジェクト モデルはあまり知られていません。かつて彼らについてブログを書いたことがあります。あまり知られていない理由の 1 つは、広く使用されている言語の中でプロトタイプによる継承を実装しているのが JavaScript だけであることです。しかし、もう一つの理由は、このオブジェクトモデルが非常に複雑で説明が難しいことだと思います。なぜこれほど複雑でわかりにくいのでしょうか?それは、JavaScript が従来のオブジェクト指向の特性を隠そうとするためであり、最終的にはその二重人格につながります (訳者注: 著者は、JavaScript にはプロセス指向とオブジェクト指向の両方の特性があると言っています)。
JavaScript オブジェクト モデルを理解して使用するのが難しいからこそ、CoffeeScript、Dart、TypeScript のようなコンパイルによって JS コードを生成できる言語があるのだと思います。
JavaScript の先駆者や熱心な人々は、JavaScript にはより優れたオブジェクト モデルがあると信じており、JavaScript が誰からも忘れ去られることを嘆いています。 JavaScript の専門家である Nicholas Zakas も、ECMAScript 6 で追加された新しいクラス構文を歓迎しています。これは、プロトタイプのスタイル構文を変更したものにすぎません。言い換えれば、従来の OOP が勝つということです。
大胆なアイデア
しかし、冗談めいたアイデアを考えてみましょう。従来のオブジェクト指向プログラミングがそれほど優れていなかった過去に旅行することを想像してください。それどころか、プロトタイプベースの継承モデルは誰にでも広く受け入れられています。何が起こるでしょうか?最終的にはどのようなデザインパターンになるのでしょうか?
もう一度想像してみましょう: JavaScript にコンストラクターや new キーワードがなかったらどうなるでしょうか?次に何が起こるでしょうか?過去に遡ってみましょう。 :)
まず第一に、JavaScript ではオブジェクト リテラルを使用して新しいオブジェクトを作成できます。以下に示すように:
var felix = {
name : 'Felix',
greet: function(){
console.log('こんにちは、' this.name '.');
}; >
次に、同じgreetメソッドを共有する複数のオブジェクトを作成できるように、greet関数を一般化して抽出し、一般的な場所に置きたいとします。これを達成するにはどうすればよいでしょうか?
いくつかのオプションがあります。まずは mixin から始めましょう。
1. Mixin(Augmentation)
JavaScript 言語では、属性の混合は非常に簡単です。混合したオブジェクトのプロパティを、混合したいオブジェクトにコピーするだけです。これを実装するには「augment」関数を使用します。コードを見ると理解できます: var Dude = {
greet: function(){
console.log('こんにちは、' this.name '.')
}
};
var felix = { name: 'Felix' };
augment(felix, Dude);//Dude の属性を felix にコピーします、つまり mixin
上記のコードでは、augment 関数が Dude オブジェクトのプロパティを felix に混合します。多くの JS ライブラリでは、拡張関数は extend と呼ばれます。一部の言語では継承を表現するために extend を使用しており、混乱するため、extend を使用するのは好きではありません。私はそれを表現するために「augment」を使用することを好みます。実際、このアプローチは継承ではなく、構文 augment(felix, Dude) は、継承ではなく Dude の属性を使用して felix を拡張していることをすでに明確に示しているからです。
おそらく、拡張コードが実装されていることはすでに推測されていると思いますが、はい、非常に簡単です。以下に示すように:
function augment(obj,プロパティ){
for (プロパティの var key){
obj[key] = property[key];
}
}
2.クローン作成 )
mixin の代替方法は、最初に Dude オブジェクトのクローンを作成し、次にクローン化されたオブジェクトに name 属性を設定することです。以下に示すように: var Dude = {
greet : function(){
console.log('こんにちは、' this.name '.');
}
}
var felix = clone(Dude);// Dude オブジェクト
felix.name = 'Felix'
をクローンします。
2 つのメソッドの唯一の違いは、プロパティが追加される順序です。クローン化されたオブジェクト内の特定のメソッドをオーバーライドする場合は、この手法の使用を検討してください。
var felix = clone(Dude); 🎜>felix .name = 'Felix';
felix.greet = function(){
console.log('Yo dawg!')
};//greet メソッドをオーバーライドします
親クラスのメソッドを呼び出す場合も非常に簡単です - 以下に示すように apply 関数を使用します
felix.greet = function(){
Dude.greet.apply(this);
this.greetingCount ; 🎜>}
これは、コンストラクターの .prototype プロパティを使用する必要がないため、プロトタイプ スタイルのコードよりもはるかに優れています。コンストラクターは使用しません。
以下はクローン関数の実装です:
function clone (obj){
var retval = {};//空のオブジェクトを作成します
augment(retval, obj);// 属性をコピーします
return retval
}
3. 継承
最後に継承です。私の意見では継承は過大評価されていますが、「インスタンス オブジェクト」間でプロパティを共有するという点で、継承にはオブジェクトの拡張よりもいくつかの利点があります。オブジェクトをパラメータとして受け取り、そのオブジェクトを継承する新しいオブジェクトを返す継承関数を作成しましょう。
継承を使用すると、同じオブジェクトから継承する複数の子オブジェクトを作成でき、これらの子オブジェクトは親オブジェクトのプロパティをリアルタイムで継承できます。以下のコードに示すように、
コードをコピー
felix.walk(); // 「ステップ、ステップ」も出力します
プロトタイプベースが使用されます継承関数内 オブジェクトの継承
コードをコピー
コードは次のとおりです。
//非標準属性 __proto__ を使用します
var ret = {};
return ret;
//どちらでもない場合サポートされている場合は、コンストラクターを使用します。 Inherit
var f = function(){};
return new f();
上記 コードの見栄えがよくありません。これは、機能モニタリングを使用して 3 つのメソッドのどれを使用するかを決定しているためです。
では、コンストラクター メソッド (つまり、初期化メソッド) をどのように使用するのでしょうか?インスタンス オブジェクト間で初期化コードを共有するにはどうすればよいですか?場合によっては、オブジェクトの一部のプロパティを設定するだけでよい場合は、上記の例のように初期化関数は必要ありません。ただし、さらに多くの初期化コードがある場合は、たとえば、initialize という初期化メソッドを使用するなどの規則を作成することもできます。次のように、initialize というメソッドが Dude で定義されていると仮定します:
コードをコピーします
コードは次のとおりです:
var Dude = {
初期化: function(){
this.greetingCount = 0;
},
次に、このようにオブジェクトを初期化できます
コードをコピーします
コードは次のとおりです:
var felix = clone(Dude);
felix.name = 'Felix';
var felix = { name: 'Felix' }
felix.name = 'Felix';
augment(felix, Dude);
var felix = assign(Dude); ';
felix.initialize();結論
つまり、上で定義した 3 つの関数 (augment、clone、inherit) を通じて、JavaScript でオブジェクトを使って何でもできるということです。コンストラクターと new キーワードを使用する必要はありません。これら 3 つの関数によって具体化されるセマンティクスは、より単純で、JavaScript の基礎となるオブジェクト システムに近いと思います。 (終わり)^_^