2013-03-19 6 views
5

プロトタイプがコンストラクタ関数に設定されている場合、instanceof演算子はプロトタイプが変更されるまでtrueを返します。どうして?instanceof演算子は継承チェーンへのその後の変更でfalseを返します

function SomeConstructorFunction() { 
} 

function extendAndInstantiate(constructorFn) { 
    constructorFn.prototype = {}; //Can be any prototype 
    return new constructorFn(); 
} 

var child1 = extendAndInstantiate(SomeConstructorFunction); 
console.log(child1 instanceof SomeConstructorFunction); //true 

var child2 = extendAndInstantiate(SomeConstructorFunction); 
console.log(child1 instanceof SomeConstructorFunction); //false 
console.log(child2 instanceof SomeConstructorFunction); //true 

答えて

3

プロトタイプの継承は、脳のベンダーのビットになる可能性があります。私はすでにプロトタイプ継承の簡単な説明を次のような答えで書いており、あなたはそれを読むことをお勧めします:https://stackoverflow.com/a/8096017/783743

あなたの質問に答えてください。次の関数を考えてみましょう:

function F() {} 

次のように私はnewを使用してFのインスタンスを作成することができます:予想f instanceof F戻りtrueとして

var f = new F; 

を。これは、instanceofオペレータがプロトタイプチェーンfF.prototypeをチェックし、そこにある場合はtrueを返すためです。私が上記にリンクした答えを見てください。

は今、私は次のように新しい機能Gを作成し、G.prototypeF.prototypeを設定すると言う:

function G() {} 

F.prototype = G.prototype; 

私は今、再びfalseが返されf instanceof Fを評価した場合。これは、F.prototypeがプロトタイプチェーンfに存在しなくなったためです(F.prototypeは今やG.prototypeです)。

今度は、Fの新しいインスタンスを作成してみましょう:

var g = new F; 

あなたがg instanceof Gを評価する場合はそれもg = new Fかかわらtrueを返します。これは、プロトタイプチェーンgG.prototypeが存在するためです。

これはバグではありません。それがJavaScriptの仕組みです。実際には、この機能を利用して興味深い機能をいくつか作成することができます:Instantiate JavaScript functions with custom prototypes

+0

プロトタイプ継承の大きな説明。私はOPの混乱は 'constructorFn.prototype = {};にあると思う。 //任意のプロトタイプにすることができます。彼はプロトタイプを同じ** value **に設定すると 'instanceof'が真となることを期待しています。代わりに同じ**リファレンス**に設定する必要があります。 – MattDiamant

+0

@MattDiamant - 私は同意します。私はOPが 'extendAndInstantiate'を使って何を達成しようとしているのか分かりませんが、私は以下の質問で私自身の' instantiate'関数のように思っています:http://stackoverflow.com/q/11490606/783743 –

+0

。最も重要なのは、プロトタイプを '{}'に設定すると、 'SomeConstructorFunction'の型が' Object'に効果的に変更されたという事実がありませんでした。 'SomeConstructorFunction.constructor'は' function Object ... 'です。 – Stephen

3
constructorFn.prototype = {}; //Can be any prototype 

ない真実!

constructorFn.prototype = Object.prototype; 

または他のネイティブプロトタイプを使用しても問題ありません。

の理由は、あなたがextendAndInstantiate()を呼び出している最初の時間は、あなたが何か(ここでは空のオブジェクト{})にSomeConstructorFunctionのプロトタイプを設定しているということです。 child1の場合、instanceOfはSomeConstructorFunctionのプロトタイプ{}の正確なインスタンスである間にのみtrueを返します。あなたが二度目extendAnInstantiate()を実行すると、あなたは、そうchild2はINSTANCEOF新しい{}になりますが、child1はそうchild1はfalseを返しますが、まだ古い{}のINSTANCEOFで、{}の別のインスタンスにSomeConstructorFunctionのプロトタイプを変更していますchild2がtrueを返します。プロトタイプを共通プロトタイプ(Object.prototypeまたはArray.prototypeなど)に設定すると、常にtrueが返されます。

これを説明する別の方法は、{}を関数から引き出し、変数objに割り当てることです。新しい{}あなたが機能を実行するたびに作成されていないため、

var obj = {}; 
function extendAndInstantiate(constructorFn) { 
    constructorFn.prototype = obj; 
    return new constructorFn(); 
} 

は今、これは常に、trueを返します。

0

instanceofは、プロトタイプオブジェクトに基づいています。

function extendAndInstantiate(constructorFn) { 
constructorFn.prototype = {}; //Can be any prototype 
... 

プロトタイプを{}に設定すると、新しいオブジェクトが作成され、プロトタイプとして設定されます。プロトタイプと同じオブジェクトではないため、instanceofはfalseを返します。

プロトタイプが同じオブジェクトになりますので、このようなセットアップは、すべてのケースのためにtrueを返します

:あなたは新しいオブジェクトが{}を使用して作成され、それはプロトタイプとして割り当てられているextendAndInstantiateを呼び出すたびに

function SomeConstructorFunction() { 
} 

var emptyObj = {}; 

function extendAndInstantiate(constructorFn) { 
    constructorFn.prototype = emptyObj; 
    return new constructorFn(); 
} 

var child1 = extendAndInstantiate(SomeConstructorFunction); 
console.log(child1 instanceof SomeConstructorFunction); //true 

var child2 = extendAndInstantiate(SomeConstructorFunction); 
console.log(child1 instanceof SomeConstructorFunction); //true 
console.log(child2 instanceof SomeConstructorFunction); //true 
0

SomeConstructorFunctionである。これにより、既存のインスタンスとSomeConstructorFunctionの間のリンクがクリアされます。最終的なものはSomeConstructorFunctionの有効なインスタンスになります。

function SomeConstructorFunction() { 

} 

function extendAndInstantiate(constructorFn) { 
    constructorFn.prototype = {}; //New instance as prototype 
    return new constructorFn(); 
} 

var child1 = extendAndInstantiate(SomeConstructorFunction); 
console.log(child1 instanceof SomeConstructorFunction); //true 

var child2 = extendAndInstantiate(SomeConstructorFunction); 
console.log(child1 instanceof SomeConstructorFunction); //false 
console.log(child2 instanceof SomeConstructorFunction); //true 


var child3 = extendAndInstantiate(SomeConstructorFunction); 
console.log(child1 instanceof SomeConstructorFunction); //false 
console.log(child2 instanceof SomeConstructorFunction); //false 
console.log(child3 instanceof SomeConstructorFunction); //true 

だからどちらかあなたは方法は、@ ben336で示した従うか、以下に示すようにプロトタイプを割り当てる前に、条件のチェックを行うことができます。

function Base(){ 

} 

function SomeConstructorFunction() { 

} 

function extendAndInstantiate(constructorFn, Base) { 
    if(!(constructorFn.prototype instanceof Base)){ 
    console.log(" extend only once "); 
    constructorFn.prototype = new Base(); 
    } 
    return new constructorFn(); 
} 


var child1 = extendAndInstantiate(SomeConstructorFunction, Base); 
console.log(child1 instanceof SomeConstructorFunction); //true 

var child2 = extendAndInstantiate(SomeConstructorFunction, Base); 
console.log(child1 instanceof SomeConstructorFunction); //true 
console.log(child2 instanceof SomeConstructorFunction); //true 


var child3 = extendAndInstantiate(SomeConstructorFunction, Base); 
console.log(child1 instanceof SomeConstructorFunction); //true 
console.log(child2 instanceof SomeConstructorFunction); //true 
console.log(child3 instanceof SomeConstructorFunction); //true 
関連する問題