wake-up-neo.net

Warum geben in JavaScript sowohl "Object instanceof Function" als auch "Function instanceof Object" true zurück?

Warum geben in JavaScript sowohl Object instanceof Function als auch Function instanceof Objecttrue zurück?

Ich habe es in Safari WebInspector versucht.

33
dinghao

Es hat eine Weile gedauert, bis ich herausgefunden habe, aber es lohnt sich wirklich. Lassen Sie uns zunächst sehen, wie instanceof funktioniert.

Zitieren aus MDN ,

Der Operator instanceof testet, ob ein Objekt die prototype-Eigenschaft eines Konstruktors in seiner Prototypkette hat.

[instanceof]

Lassen Sie uns nun sehen, wie instanceof durch die ECMA 5.1-Spezifikation definiert ist.

Die Produktion RelationalExpression: RelationalExpression instanceof ShiftExpression wird wie folgt bewertet:

  1. Sei lref das Ergebnis der Auswertung von RelationalExpression.
  2. Sei lvalGetValue(lref).
  3. Sei rref das Ergebnis der Auswertung von ShiftExpression.
  4. Sei rvalGetValue(rref).
  5. Wenn Type(rval) nicht Object ist, lösen Sie eine TypeError-Ausnahme aus.
  6. Wenn rval keine interne Methode [[HasInstance]] hat, geben Sie eine TypeError-Ausnahme aus.
  7. Gibt das Ergebnis des Aufrufs der internen Methode [[HasInstance]] von rval mit dem Argument lval zurück.

Zuerst werden die Ausdrücke für die linke und rechte Seite ausgewertet (GetValue), und das Ergebnis auf der rechten Seite sollte eine Object mit [[HasInstance]] interner Methode sein. Nicht alle Objekte verfügen über eine [[HasInstance]] interne Methode, sondern über Funktionen. Zum Beispiel wird Folgendes fehlschlagen

console.log(Object instanceof {});
# TypeError: Expecting a function in instanceof check, but got #<Object>

[[HasInstance]]

Lassen Sie uns nun sehen, wie [[HasInstance]] in der ECMA 5.1-Spezifikation definiert wurde.

Angenommen, F ist ein Funktionsobjekt.

Wenn die interne Methode [[HasInstance]] von F mit dem Wert V aufgerufen wird, werden die folgenden Schritte ausgeführt:

  1. Wenn V kein Objekt ist, geben Sie false zurück.
  2. Sei O das Ergebnis des Aufrufs der internen Methode [[Get]] von F mit dem Eigenschaftennamen "prototype".
  3. Wenn Type(O) nicht Object ist, lösen Sie eine TypeError-Ausnahme aus.
  4. Wiederholen 
    1. Sei V der Wert der internen Eigenschaft [[Prototype]] von V.
    2. Wenn Vnull ist, geben Sie false zurück.
    3. Wenn sich O und V auf dasselbe Objekt beziehen, geben Sie true zurück.

Es ist so einfach. Nehmen Sie die prototype-Eigenschaft von F und vergleichen Sie sie mit der [[Prototype]]-internen Eigenschaft von O, bis sie null wird oder prototype von F mit O identisch ist.

[[prototype]] interne Eigenschaft

Zuerst sehen wir uns die interne Eigenschaft [[prototype]] an ,

Alle Objekte haben eine interne Eigenschaft namens [[Prototype]]. Der Wert dieser Eigenschaft ist entweder null oder ein Objekt und wird zum Implementieren der Vererbung verwendet. Ob ein natives Objekt ein Host-Objekt als [[Prototype]] haben kann, hängt von der Implementierung ab. Jede [[Prototype]]-Kette muss eine endliche Länge haben (das heißt, ausgehend von einem beliebigen Objekt muss der rekursive Zugriff auf die interne Eigenschaft [[Prototype]] letztendlich zu einem null-Wert führen).

Hinweis: Wir können diese interne Eigenschaft mit der Funktion Object.getPrototypeOf erhalten.

prototype-Eigenschaft

[[HasInstance]] spricht auch von einer anderen Eigenschaft namens prototype , die für die Function-Objekte spezifisch ist.

Der Wert der prototype-Eigenschaft wird zum Initialisieren der [[Prototype]]-internen Eigenschaft eines neu erstellten Objekts verwendet, bevor das Function-Objekt als Konstruktor für das neu erstellte Objekt aufgerufen wird. 

Das heißt, wenn ein Funktionsobjekt als Konstruktor verwendet wird, wird ein neues Objekt erstellt, und das neue Objekt wird mit seinem [[Prototype]] mit dieser prototype-Eigenschaft initialisiert. Zum Beispiel,

function Test() {}
Test.prototype.print = console.log;
console.log(Object.getPrototypeOf(new Test()) === Test.prototype);
# true

Tatsächliches Problem

Kommen wir nun zur eigentlichen Frage zurück. Nehmen wir den ersten Fall

console.log(Object instanceof Function);
# true

Zuerst wird Function.prototype abgerufen und versucht zu finden, ob sich dieses Objekt in der Prototyphierarchie von Object befindet. Mal sehen, wie sich das herausstellt

console.log(Function.prototype);
# [Function: Empty]
console.log(Object.getPrototypeOf(Object));
# [Function: Empty]
console.log(Object.getPrototypeOf(Object) === Function.prototype);
# true

Da Function.prototype mit der internen Eigenschaft [[Prototype]] der Object übereinstimmt, wird true zurückgegeben.

Nehmen wir nun den zweiten Fall

console.log(Function instanceof Object);
# true
console.log(Object.prototype);
# {}
console.log(Object.getPrototypeOf(Function));
# [Function: Empty]
console.log(Object.getPrototypeOf(Function) === Object.prototype);
# false
console.log(Object.getPrototypeOf(Object.getPrototypeOf(Function)));
# {}
Object.getPrototypeOf(Object.getPrototypeOf(Function)) === Object.prototype
# true

Hier erhalten wir zuerst den Object.prototype, der {} ist. Jetzt versucht es herauszufinden, ob dasselbe Objekt {} in der Prototypkette der Function vorhanden ist. Unmittelbare übergeordnete Komponente von Function ist und eine leere Funktion.

console.log(Object.getPrototypeOf(Function));
# [Function: Empty]

Es ist nicht das Gleiche wie Object.prototype

console.log(Object.getPrototypeOf(Function) === Object.prototype);
# false

Aber der [[HasInstance]]-Algorithmus hört hier nicht auf. Es wiederholt sich und steht eine weitere Ebene auf

console.log(Object.getPrototypeOf(Object.getPrototypeOf(Function)));
# {}

Und das ist dasselbe wie Object.prototype. Deshalb wird true zurückgegeben.

37
thefourtheye

Von MDN :

Der Operator instanceof prüft, ob ein Objekt die Prototypeneigenschaft eines Konstruktors in seiner Prototypkette hat.

Im Wesentlichen wird geprüft, ob Object (nicht eine Instanz von Object, sondern der Konstruktor selbst) eine Instanz von Function.constructor irgendwo in seiner Prototypkette hat.

Und in der Tat:

> Function.__proto__.__proto__ === Object.prototype
true
> Object.__proto__ === Function.prototype
true

Dies erklärt, warum Object instanceof Function ebenso wie umgekehrt.

14

ALLE Objekte haben eine interne Eigenschaft namens [[Prototyp]]. Der Wert dieser Eigenschaft ist entweder null oder ein Objekt und wird zur Implementierung der Vererbung verwendet. Wenn Sie versuchen, einen Schlüssel in einem Objekt nachzuschlagen, und dieser nicht gefunden wird, sucht JavaScript in der Prototypkette nach dem Schlüssel.

Der Funktionskonstruktor erstellt neue Funktionsobjekte (Instanzen des Funktionskonstruktors). Die Prototypeneigenschaft ist spezifisch für Funktionsobjekte. Der Funktionskonstruktor ist selbst ein Funktionsobjekt (Instanz des Funktionskonstruktors).

Wenn ein Funktionsobjekt als Konstruktor verwendet wird, wird ein neues Objekt erstellt, und das [[Prototyp]] des neuen Objekts wird mit der Prototypeneigenschaft des Konstruktors initialisiert.

function Dog () {}
var myCrazyDog = new Dog();
myCrazyDog.__proto__ === Dog.prototype // true

Die Sprachspezifikation ist, dass alle Objekte Instanzen des Objektkonstruktors und alle Funktionen Instanzen des Funktionskonstruktors sind.

Objektinstanz von Funktion ist wahr weil Objekt eine Funktion und somit eine Instanz von Funktion ist (Objekt ist ein Funktionsobjekt - eine Instanz des Funktionskonstruktors). Objekt erbt von Function.prototype.

console.log(Object instanceof Function)                         // true
console.log(Object.__proto__ === Function.prototype)            // true

Objektinstanz von Objekt ist wahr , weil Objekt von Function.prototype erbt. Da Function.prototype ein Objekt ist, erbt es von Object.prototype. Die Funktionsinstanz von Object ist true , da die Funktion von Function.prototype erbt. Da Function.prototype ein Objekt ist, erbt es von Object.prototype. Die Prototypkette sieht folgendermaßen aus:

Object ---> Function.prototype ---> Object.prototype ---> null
Function ---> Function.prototype ---> Object.prototype ---> null

console.log(Object instanceof Object)                               // true
console.log(Object.__proto__ === Function.prototype)                // true
console.log(Object.__proto__.__proto__ === Object.prototype)        // true
console.log(Function instanceof Object)                             // true
console.log(Function.__proto__ === Function.prototype)              // true
console.log(Function.__proto__.__proto__ === Object.prototype)      // true

Funktionsinstanz von Funktion ist wahr . Funktion ist eine Instanz von sich selbst (natürlich, da es sich um eine Funktion und somit um eine Instanz von Function handelt). Die Prototypkette sieht folgendermaßen aus:

Function ---> Function.prototype ---> Object.prototype ---> null

console.log(Function instanceof Function)                           // true
console.log(Function.__proto__ === Function.prototype)              // true
console.log(Function.__proto__.__proto__ === Object.prototype)      // true

Denken Sie also daran, dass die Konstruktoren Function () und Object () Funktionen sind. Da es sich um Funktionen handelt, handelt es sich um Instanzen des Function () - Konstruktors, die von Function.prototype erben. Da Function.prototype ein Objekt ist, ist Function.prototype eine Instanz von Object und erbt somit von Object.prototype.

console.log(Object instance of Function)                    // true
console.log(Function instance of Function)                  // true
console.log(Function.prototype instanceof Object);          // true
6
misterd89

Die Quelle der Verwirrung in Ihrer Frage liegt in der inhärenten Doppelnatur von Funktionen * in JavaScript (ECMAScript). 

Funktionen in js sind sowohl reguläre Funktionen als auch Objekte zur gleichen Zeit. Betrachten Sie sie als algorithmisch Dr. Jekyll und Mr. Hyde . Sie sehen aus wie Objekte auf der Außenseite, aber innen sind es nur Ihre guten alten Js-Funktionen mit all ihren Macken, oder vielleicht ist es umgekehrt!

JavaScript ist wirklich ein kniffliges Geschäft :)

Zurück zu Ihrer Frage, die Syntax aus dem MDN entlehnt: 

object instanceof constructor 

Anwenden auf die erste Anweisung in Ihrem Code: 

Object instanceof Function

Hier haben Sie Object, eine Konstruktorfunktion, die als Objektinitialisierer verwendet wird, aber da Funktionen in js ein Doppelleben führen, sind ihr objektspezifische Requisiten und Methoden zugeordnet, sodass sie auch ein Objekt sind. 

Die erste Bedingung in der Anweisung wurde erfüllt. Wir müssen die andere Bedingung oder den Operanden untersuchen. 

Wie Sie vielleicht bemerkt haben, ist Function auch ein Funktionskonstruktor, aber die andere Objektseite ist für uns jetzt während der Ausführung dieser bestimmten Anweisung uninteressant. 

Die syntaktischen Bedingungen sind also beide erfüllt, nämlich "Objekt" und "Konstruktor". Wir können jetzt damit fortfahren, ihre erblicheBeziehung zu untersuchen und ob zwischen ihnen eine Verbindung besteht. 

Da Object selbst eine Arbeitsfunktion ist, ist es sehr sinnvoll anzunehmen, dass ihre interne Prototyp-Requisite auf die Function.prototype-Objektreferenz verweist, da in jsALLfunction vererben deren Requisiten und Methoden durch denselben Ort Function.prototype

true ist definitiv dasONLYerwartete Ergebnis dieses Vergleichs, das vom instanceof-Operator durchgeführt wird.

Für den anderen Fall: 

Function instanceof Object

Da wir bereits festgestellt haben, dass Funktionen in js auch eine Objektseite haben. Es ist sinnvoll, dass sie ihr ausgefallenes objektspezifisches Spielzeug aus dem Object.prototype erhalten haben und daher Instanzen des Objektkonstruktors darstellen. 

Ich hoffe, dass ich mit meinen Erklärungen und Allegorien nicht zu der Verwirrung beigetragen habe. :) 

*: Nicht nur Funktionen, die in js ein Doppelleben führen. Fast alle Datentypen in js haben eine dunkle Seite, die das Ausführen von Operationen und Manipulationen erleichtert.

3
Mr. X

Die schlechteste Eigenschaft ist eigentlich, dass Function eine Instanz von sich selbst ist. Function instanceof Function gibt true zurück.

Es wird in Kannan's Das überraschend elegante Javascript-Typmodell , unter http://web.archive.org/web/20140205182624/http://vijayan.ca/blog/2012/02/ erläutert. 21/javascript-type-model

Zitat am Ende der Erklärung:

Ja, das bedeutet, dass Funktion eine Instanz von sich selbst ist (natürlich, da es sich um eine Funktion und somit um eine Instanz von Function handelt). Dies ist etwas, mit dem wir uns alle wissentlich oder nicht lange beschäftigt haben - alle Konstruktorfunktionen sind reguläre Funktionen und damit Instanzen von Function, und Function selbst ist nur die Konstruktorfunktion zum Konstruieren anderer Funktionen, also auch eine Instanz von Function.

 enter image description here

1
Aurélien Ribon

Sehr einfache Erklärung, anders als alle Antworten

Sowohl Object als auch Function sind Konstruktoren (Typ von beiden mit Rückgabe "Funktionsobjekte"), und beide werden vom Function Constructor erstellt. Die __proto__-Eigenschaft beider zeigt auf das 'Function.prototype'-Objekt.

SCHNELLE ERKLÄRUNG: Die __proto__-Eigenschaft eines Objekts (z. B. p1, bei der es sich um einen Personentyp handelt) zeigt auf das Prototyp des Konstruktors (z. B. person.prototype). Wieder zeigt das __proto__ in der Prototypkette auf das Objekt "Object.prototype".

VOR DEM LESEN WEITERER DRUCKDETAILS AUF CHROME CONSOLE console.dir (Objekt), console.dir (Funktion)

KEEP IN MIND, Funktionskonstruktoren und auch Objekte, so dass Sie beide .prototype- und __proto__-Eigenschaften sehen. In allen Instanzobjekten (z. B. p1) finden Sie nur die Eigenschaft __proto__. Das __proto__ ist ein Accessor für die versteckte Eigenschaft [[Prototye]] und der beste Weg, um es zu erhalten, ist Object.getPrototypeOf (p1), da __proto__ depricated ist.

(p1 Instanz von Person) Hier prüft der Operator, ob der Prototyp der Konstrukteur Person in der Prototypkette des Objekts p1 enthalten ist. Beachten Sie, dass der erste Wert ein Instanzobjekt (p1) und der zweite Wert ein Konstruktor (Person) ist.

Lets analyse => Funktionsinstanz von Object.

Das __proto __.__ proto__ des Funktionsobjekts zeigt auf Object.prototype. Also ist es wahr

Lassen Sie uns analysieren => Objektinstanz der Funktion.

__Proto__ des Objektobjekts zeigt auf Function.prototype, also ist es wahr

Hoffe das hilft.

0
Sumer