2013-03-19 4 views
5

Wenn ein Prototyp für eine Konstruktorfunktion festgelegt wird, gibt der Operator instanceof nur true zurück, bis der Prototyp geändert wird. Warum?instanceof-Operator gibt false bei der nachfolgenden Änderung der Vererbungskette zurück

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 

Antwort

3

Prototypische Vererbung kann ein bisschen ein Brain Bender sein. Ich habe bereits eine einfache Erklärung für prototypische Vererbung in der folgenden Antwort geschrieben und ich schlage vor, Sie lesen es: https://stackoverflow.com/a/8096017/783743

Jetzt, um Ihre Frage zu beantworten.Betrachten Sie die folgende Funktion:

function F() {} 

ich eine Instanz von Fnew Verwendung erstellen können wie folgt:

var f = new F; 

Als truef instanceof F Renditen erwartet. Dies liegt daran, dass der Operator instanceof in der Prototypkette von f nach F.prototype sucht und true zurückgibt, wenn er da ist. Siehe die Antwort, die ich oben verlinkt habe.

Nun sage ich eine neue Funktion G wie folgt erstellen und setzen F.prototype-G.prototype:

function G() {} 

F.prototype = G.prototype; 

Wenn ich jetzt bewerten f instanceof F wieder false zurückgegeben. Dies liegt daran, dass sich F.prototype nicht mehr in der Prototypkette von f befindet (denken Sie daran, dass F.prototype jetzt G.prototype ist).

Lassen Sie uns nun eine neue Instanz von F erstellen:

var g = new F; 

Wenn Sie bewerten g instanceof G es true obwohl g = new F zurückkehren werde. Dies liegt daran, dass G.prototype in der Prototypkette von g existiert.

Dies ist kein Fehler. So funktioniert JavaScript. Tatsächlich können wir diese Funktion nutzen, um einige wirklich interessante Funktionen zu erzeugen: Instantiate JavaScript functions with custom prototypes

+0

Große Erklärung der prototypischen Vererbung. Ich denke, die Verwirrung von OP liegt in 'constructorFn.prototype = {}; // Kann jeder Prototyp sein. Er erwartet, dass das Setzen des Prototyps auf den gleichen ** Wert ** dazu führt, dass "instanceof" wahr ist, wenn sie stattdessen auf die gleiche ** Referenz ** gesetzt werden sollen. – MattDiamant

+0

@MattDiamant - stimme zu. Ich weiß nicht, was das OP mit "extendAndInstantiate" zu erreichen versucht, aber ich glaube, es ist ein bisschen wie meine eigene 'instanziate'-Funktion in der folgenden Frage: http://stackoverflow.com/q/11490606/783743 –

+0

Gute Erklärung . Am wichtigsten ist, dass mir die Tatsache fehlte, dass man den Typ von 'SomeConstructorFunction' in' Object' ändert, wenn man den Prototyp auf '{}' setzt. 'SomeConstructorFunction.constructor' ist' function Object ...'. – Stephen

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

Nicht wahr!

constructorFn.prototype = Object.prototype; 

Oder jeder andere native Prototyp wird sie alle wahr machen.

Der Grund ist, dass Sie beim ersten Aufruf von extendAndInstantiate() den Prototyp der SomeConstructionFunction auf etwas setzen (hier ein leeres Objekt {}). Für child1 liefert instanceOf nur wahr, während der Prototyp von SomeConstructorFunction genau diese Instanz von {} ist. Wenn Sie extendAnInstantiate() ein zweites Mal ausführen, werden Sie SomeConstructorFunction ‚s-Prototyp auf eine andere Instanz von {} ändern, so wird child2 ein instanceOf sein, dass neue {}, aber child1 ist immer noch ein instanceOf der alten {}, so wird child1 false zurück, während child2 wahr zurückgibt. Wenn Sie den Prototyp auf einen gemeinsamen Prototyp setzen, z. B. Object.prototype oder Array.prototype, wird immer der Wert true zurückgegeben.

Eine andere Möglichkeit, dies zu veranschaulichen, besteht darin, {} aus der Funktion herauszunehmen und einer Variablen obj zuzuweisen.

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

Nun wird dies immer true zurück, weil Sie keine neue {} jedes Mal, wenn Sie die Funktion ausführen zu schaffen sind.

0

instanceof basiert auf dem Prototyp-Objekt.

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

Wenn Sie den Prototyp auf {} setzen, erstellen Sie ein neues Objekt und legen es als Prototyp fest. Weil es dann nicht dasselbe Objekt wie der Prototyp ist, gibt instanceof false zurück.

Ein Setup wie dies für alle Fälle true zurück, weil der Prototyp das gleiche Objekt sein wird:

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

Jedes Mal, wenn Sie extendAndInstantiate rufen ein neues Objekt erstellt wird {} und wird als Prototyp zugeordnet von SomeConstructorFunction. Dies löscht die Verbindung zwischen vorhandenen Instanzen und SomeConstructorFunction. Also nur die letzte wird eine gültige Instanz von SomeConstructorFunction sein.

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 

So können Sie entweder die Methode @ ben336 oder führen Sie eine Zustandsüberprüfung, bevor die Zuordnung Prototyp wie unten dargestellt folgen zeigte.

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 
Verwandte Themen