3

JavaScript で「クラス」を定義するこれら 2 つの方法の違いは何ですか?

方法 1

コンストラクター内でメソッドを定義します。

function MyClass()
{
    this.foo = function() { console.log('hello world!'); };
}

方法 2

プロトタイプでメソッドを定義します。

function MyClass()
{}

MyClass.prototype.foo = function() { console.log('hello world!'); };
4

2 に答える 2

4

1 つ目はオブジェクトのインスタンス化ごとに新しい関数オブジェクトを作成し、2 つ目はプロトタイプ メソッドへの参照を各インスタンスに割り当てます。つまり、すべてのインスタンスが単一の関数オブジェクトを共有するため、2 番目の方法がより効率的です。

これは単なるプロトタイプ チェーンのロジックであり、任意のオブジェクトを介してあらゆるものにアクセスしようとすることができます。

var objLiteral = {foo:'bar'};

JS にアクセスするときobjLiteral.foo、オブジェクト自体が定義したプロパティを最初に調べ、見つかった場合は値を返します。JS がオブジェクト自体のプロパティを見つけられない場合、オブジェクトのプロトタイプをチェックします。したがって、次のようになります。

objLiteral.valueOf();//method defined @Object.prototype
objLiteral.valueOf === Object.prototype.valueOf //true

しかし、最初の方法を使用する場合:

function SomeConstructor()
{
    this.methd = function()
    {
        return true;
    }
}
var f = new SomeConstructor();
var g = new SomeConstructor();
f.methd === g.methd;//FALSE!

これは、2 つの別個の関数オブジェクトを扱っていることを示しています。関数定義をプロトタイプに移動すると、f.methd === g.methd;true になります。

function SomeConstructor()
{
}
SomeConstructor.prototype.methd = function()
{
    return true;
}
var f = new SomeConstructor();
var g = new SomeConstructor();
f.methd === g.methd;//true!

あなたのコメントに応えて:

プロトタイプ レベルでメソッドを定義すると、特定のタスクのメソッドを変更してから、デフォルトの動作に「リセット」することができます。AJAX リクエストを作成する関数にいるとします。

someObject.toString = function(){ return JSON.stringify(this);}
//when concatinating this object you'll get its json string
//do a lot of stuff
delete (someObject.toString);

ここでも JS は、オブジェクト自体toStringにプロパティが定義されているかどうかを確認します。そのため、JS はプロパティに割り当てた関数を削除します。次回が呼び出されると、JS はプロトタイプ チェーンのスキャンをもう一度開始し、最初に出現したメソッド (プロトタイプ内) を使用します。明確にしましょう:toStringtoString

function SomeConstructor()
{
}
SomeConstructor.prototype.methd = function()
{
    return true;
}
var f = new SomeConstructor();
var g = new SomeConstructor();
f.methd = function(){return false;};
g.methd();//returns true, still <-- method is gotten from the prototype
f.methd();//returns false <-- method is defined @ instance level
delete (f.methd);
f.methd();//returns true, f doesn't have the method, but the prototype still does, so JS uses that.

さらに良いことに、インスタンスのメソッドを別のプロトタイプのメソッドに置き換えることもできます。

f.methd = Object.prototype.valueOf;//for as long as you need

f にはすでにメソッドがあるため、最後の例は無意味ですvalueOf。その継承チェーンは次のようになります: var f ---> SomeConstructor ---> Object、すべての Object.prototype メソッドにもアクセスできます! いいですね。

これらはダミーの例に過ぎませんが、これが JS を信じられないほど柔軟な (時には柔軟性がありすぎることは認めざるを得ません) 表現力豊かな言語にしている機能の 1 つであることを理解していただければ幸いです。

于 2012-09-05T15:14:29.460 に答える
2

最初のケースでは、関数はインスタンスごとに作成されfoo、オブジェクトのプロパティに設定されます。2 番目のケースでは、共有機能です。呼び出すobj.propと、オブジェクト自体で検索し、そこにない場合はprotoオブジェクトで検索し、というように呼び出されchain of prototypesます。

たとえば、このコードは次を提供しますfoo

function MyClass() {
  this.foo = function () {};
}

var myVariable = new MyClass();
for (var i in myVariable) if (myVariable.hasOwnProperty(i)) console.log(i);

しかし、これはそうではありません:

function MyClass() {
}

MyClass.prototype.foo = function () {};

var myVariable = new MyClass();
for (var i in myVariable) if (myVariable.hasOwnProperty(i)) console.log(i);
于 2012-09-05T15:13:52.903 に答える