Gibt es eine Umgebung-agnostische Möglichkeit, Javascript-Host-Objekte zu erkennen?

8

Ich schreibe eine Javascript-Stacktrace-Bibliothek. Die Bibliothek muss erkennen, ob ein bestimmtes Objekt oder eine Funktion vom Programmierer erstellt wurde oder als Teil der Umgebung vorhanden war (einschließlich integrierter Objekte). Host-Objekte werden aufgrund ihres unvorhersehbaren Verhaltens ein wenig problematisch. Daher bin ich auf der Suche nach einer Umgebung, um festzustellen, ob ein bestimmtes Objekt in Javascript ein Host-Objekt ist (siehe ECMAScript 3 - 4.3.8). Die Unterscheidung von Host-Objekten von nativen Objekten und primitiven Werten ist jedoch für Programmierer in anderen Projekten nützlich, insbesondere in browserlosen Umgebungen. Daher möchte ich mich auf diese konzentrieren und nicht auf die Probleme, die Host-Objekte in meiner Bibliothek verursachen -created Objekte.

Bisher war ich nur in der Lage, Lösungen zu finden, die von der Umgebung abhängen, in der JavaScript-Code läuft. Zum Beispiel:

%Vor%

Ich habe bemerkt, dass jQuerys eigene Methode isPlainObject () auch von der Umgebung abhängig ist und dass die Logik eher verworren ist .

Vielleicht liegt das daran, dass das Wesen der Bestie mit Wirtsobjekten übereinstimmt (da ihr Verhalten von der Umgebung bestimmt wird), aber ich würde gerne etwas weiter graben, um zu sehen, ob das möglich ist und mich gefragt habe, ob jemand überfahren ist Dieses spezielle Problem vor und hat eine Lösung bereit.

Also. Kennt jemand eine einfache plattformunabhängige Lösung zum Testen von Hostobjekten? Und wenn es in einer browserlosen Umgebung wie Node oder Rhino läuft, ist es umso besser.

Mögliche Ansätze (die möglicherweise nicht funktionieren):

  • Das Testen auf Eigenschaften von Hostobjekten scheint eine verlorene Ursache zu sein, da es keine Spezifikation für ihr Verhalten gibt. Es kann jedoch möglich sein, zu testen, ob das Objekt Teil der ES3-Spezifikation ist.
  • Ich habe versucht, Object.prototype.toString() zu verwenden, da es ziemlich genau definiert ist, aber die Ergebnisse sind nicht eindeutig, da einige Umgebungen (nämlich IE) denselben Wert für native und Host-Objekte angeben.
  • Es kann möglich sein, dies zu tun, indem überprüft wird, ob das ultimative constructor eines Objekts durch die Prototypkette tatsächlich ein instanceof Function ist.
Steven de Salas 27.12.2011, 14:24
quelle

5 Antworten

5

Wenn Sie sich die Definition des Hostobjekts ansehen - "Objekt, das von der Hostumgebung zur Verfügung gestellt wird die Ausführungsumgebung von ECMAScript. " - es wird ziemlich klar, dass es keine einfache Möglichkeit gibt zu bestimmen, ob ein Objekt ein Host oder ein natives Objekt ist.

Im Gegensatz zu nativen Objekten definieren Hostobjekte interne Eigenschaften (z. B. [[Prototyp]], [[Klasse]] usw. implementierungsspezifisch. Das liegt daran, dass die Spezifikation dies zulässt . Es gibt jedoch keine "MUSS" -Anforderung für Host-Objekte, um internes Verhalten in implementierungsspezifischer Weise zu implementieren; es ist eine "MAY" Art von Anforderung. Darauf können wir uns nicht verlassen. Diese Objekte können oder können nicht "komisch" wirken. Es gibt keine Möglichkeit zu sagen.

Es gab wenige Versuche, Host-Objekte in der Vergangenheit zu erkennen, aber alle basieren offensichtlich auf Beobachtungen bestimmter Umgebungen (MSHTML-DOM ist einer davon) - denken Sie daran, dass Host-Objekte kein eindeutiges Muster haben / Eigenschaft, um sich zu identifizieren. Peter Michaux dokumentierte die meisten Schlussfolgerungen hier (siehe " Feature Testen eines Host-Objekts "Abschnitt). Das berüchtigte typeof ... == "unknown" stammt von MSHTML DOM und seinen ActiveX-basierten Host-Objekten. Beachten Sie, dass Peter über Host-Objekte hauptsächlich im Zusammenhang mit Browser-Skripten spricht und die Prüfungen auf "Ist das eine Host-Methode?", "Ist das ein Host Objekt Objekt", etc. p>

In einigen Umgebungen erben Host-Objekte nicht von Object.prototype (wodurch es einfach zu überprüfen ist) oder haben bestimmte Eigenschaften, die Fehler (zB "Prototyp" auf einigen "Interface" -Objekten im IE) auslösen oder sogar werfen Fehler beim Zugriff selbst.

Es könnte so aussehen, als könnten Sie einfach prüfen, ob ein Objekt zu den in der Spezifikation definierten gehört, und wenn nicht, dann betrachten Sie es als Host. Aber das wird nicht wirklich helfen; es würde Ihnen nur Objekte geben, die nicht eingebaut sind . Einige dieser Nicht-Standardobjekte könnten immer noch nativ sein (was bedeutet, dass sie die übliche Semantik wie in der Spezifikation beschrieben implementieren würden).

Am besten testen Sie auf ein bestimmtes Verhalten Ihrer App / Ihres Skripts, auf das die Host-Objekte möglicherweise empfindlich reagieren. Dies ist immer der sicherste Weg. Planen Sie, auf etwas von einem Objekt zuzugreifen? Etwas vom Objekt löschen? Etwas zum Objekt hinzufügen? Testen Sie es. Sehen Sie, ob es funktioniert. Wenn dies nicht der Fall ist, handelt es sich wahrscheinlich um ein Host-Objekt.

    
kangax 28.12.2011 05:58
quelle
4

Hier ist eine neuere Version von isNative , die alle Objekte mit einer nativen Implementierung für toString ablehnt, was das Problem für die Stack-Trace-Bibliothek löst, aber die hier gestellte Frage nicht befriedigend beantwortet. Wenn dieser Ansatz fehlschlägt, filtert er alle eingebauten Typdefinitionen wie Object , Date , String , Math usw. heraus, die selbst keine Host-Objekte sind. Diese Lösung hängt auch davon ab, wie die Umgebung native / integrierte Funktionsdefinitionen ausgibt (sie muss "[nativen Code]" enthalten, damit die Funktion funktioniert). Da das Verhalten der Funktion unterschiedlich ist, wurde sie in isUserObject umbenannt.

%Vor%

Hier ist eine Liste von JsFiddle-Tests , mit der Sie dies in verschiedenen Browsern testen können.

%Vor%     
outis 15.02.2012 02:42
quelle
2

FAST SOLVED

Fast hat es geschafft, das zum Laufen zu bringen.

Die Lösung liegt darin, dass Host-Objekte manchmal nicht von nativen unterschieden werden können. Der folgende Code schlägt beim Testen von isNative(window.alert) in Chrome fehl, da die Webkit-Engine eine alert -Funktion definiert, die (bis jetzt) ​​identisch mit einer nativen aussieht.

Es verwendet einfaches JavaScript gemäß ES3 und basiert auf dem Testen, dass ein Objekt nativ ist (im Gegensatz zum Host-Objekt). Gemäß ES3-Definition von Host-Objekten: 'Jedes Objekt, das nicht nativ ist, ist ein Host-Objekt.' Diese Funktion kann zum Erkennen von Host-Objekten verwendet werden.

%Vor%

Hier ist eine Liste von JsFiddle-Tests , mit der Sie dies in IE / Firefox / Chrome testen können.

Ich habe nicht-Browser-Umgebungen getestet, da es ein bisschen mühsamer ist, aber da der Code so einfach ist, denke ich nicht, dass es irgendwelche Probleme haben wird.

%Vor%     
Steven de Salas 04.01.2012 11:33
quelle
0

Ich glaube, dass die Natur von Host-Objekten bedeutet, dass es keine einfache, umwelt-agnostische Möglichkeit gibt, sie zu erkennen. Siehe diese Diskussion auf SO für mehr, wenn Sie es sind neugierig.

Wie Sie festgestellt haben, hat das jQuery-Projekt versucht, Host-Objekte zu erkennen und dabei auf ähnliche Probleme gestoßen. Die Diskussion auf dieser Seite ist sehr aufschlussreich.

    
Josh Smith 27.12.2011 15:11
quelle
0

Ich habe eine Idee, die möglicherweise nicht in allen Kontexten anwendbar ist.

Stellen Sie sicher, dass Ihr Skript das erste ist, das ausgeführt werden soll, und wickeln Sie es ähnlich wie JS-Frameworks in closure ein.
Dann Schleife durch alle Objekte in Ihrem globalen Bereich (Wenn Sie auf etwas sind, das kein Browser ist, window wird nicht definiert; daher am Anfang des Skripts ein window = this ), und Schleife durch die untergeordneten Elemente usw. . Alle Objekte außer Ihrem werden Host-Objekte sein! Dann können Sie das zu einer lokalen Datenbank hinzufügen oder sogar speichern und der laufenden Umgebung zur zukünftigen Verwendung zuordnen.

    
Camilo Martin 27.12.2011 15:36
quelle