Andreas Rozek Lesehinweise letzte Änderungen Gästebuch-Eintrag Mitteilungen an den Autor  English Version  zur Leitseite zum vorherigen Thema zum nächsten Thema  zur ersten Seite zur vorherigen Seite zur nächsten Seite

Rhino_02 - Erkennung von Datentypen

"Rhino_02" untersucht, wie man innerhalb eines JavaScript-Makros den Datentyp eines (z.B. als Aufruf-Parameter an eine Funktion übergebenen) Objektes ermitteln kann.

Zu diesem Zweck werden nacheinander Instanzen aller von JavaScript unterstützten Datentypen (sowie einer "Benutzer-definierten" "Klasse") an eine Funktion "checkTypeOf" übergeben, in welcher das jeweilige Objekt genauer untersucht wird. Das Ergebnis dieser Untersuchung wird auf "stdout" dokumentiert.

Der eigentliche Kern des Programmes steckt in der Funktion "checkTypeOf":
 

/*******************************************************************************
*                                                                              *
* checkTypeOf        investigates the type characteristics of a given argument *
*                                                                              *
*******************************************************************************/

  function checkTypeOf (Name, Candidate) {
    println(" - typeof(", Name, ") = ", typeof(Candidate));

    try {
      SuperClassesFound = 0;                                 // global variable!
        if (Candidate instanceof Object)   reportInstanceOf(Name, "Object");
        if (Candidate instanceof Boolean)  reportInstanceOf(Name, "Boolean");
        if (Candidate instanceof Number)   reportInstanceOf(Name, "Number");
        if (Candidate instanceof String)   reportInstanceOf(Name, "String");
        if (Candidate instanceof Array)    reportInstanceOf(Name, "Array");
        if (Candidate instanceof Function) reportInstanceOf(Name, "Function");
        if (Candidate instanceof Date)     reportInstanceOf(Name, "Date");
      if (SuperClassesFound > 0) {
        println();                                         // finish output line
      } else {
        println(" - ", Name, " has no (intrinsic) superclass");
      };
    } catch (Signal) {
      /* nop */      // an exception is thrown during examination of "undefined"
    };

    PrototypesFound = 0;                                     // global variable!
      if   (Object.prototype.isPrototypeOf(Candidate)) reportPrototype(Name, "Object");
      if  (Boolean.prototype.isPrototypeOf(Candidate)) reportPrototype(Name, "Boolean");
      if   (Number.prototype.isPrototypeOf(Candidate)) reportPrototype(Name, "Number");
      if   (String.prototype.isPrototypeOf(Candidate)) reportPrototype(Name, "String");
      if    (Array.prototype.isPrototypeOf(Candidate)) reportPrototype(Name, "Array");
      if (Function.prototype.isPrototypeOf(Candidate)) reportPrototype(Name, "Function");
      if     (Date.prototype.isPrototypeOf(Candidate)) reportPrototype(Name, "Date");
    if (PrototypesFound > 0) {
      println();                                           // finish output line
    };

    try {
      if ("constructor" in Candidate) println(" - ", Name, " has a constructor");
    } catch (Signal) {
      /* nop */
    };

    try {
      if ("prototype" in Candidate) println(" - ", Name, " has a prototype");
    } catch (Signal) {
      /* nop */
    };
  };

Als erstes wird geprüft, wie die Funktion "typeof()" auf das Objekt reagiert. Anschließend wird mithilfe des instanceof-Operators untersucht, ob sich das Test-Objekt von einem der intrinsischen Datentypen ableitet. Auf ähnliche Weise wird überprüft, ob das Objekt Datenfelder und Methoden aus einem der intrinsischen Prototypen übernimmt. Zu guter Letzt wird mithilfe des in-Operators explizit nach einem Konstruktor und einem Prototypen für das Test-Objekt gesucht.

Schlechte Erfahrungen mit früheren Versionen des Programmes haben dazu geführt, daß einige Passagen der Funktion als try-catch-Block ausgeführt werden mußten - mit mäßigem Erfolg (siehe dazu auch die nachstehende Programmausgabe).

"Rhino_02" wird ohne Kommandozeilen-Argumente aufgerufen

  java Rhino Rhino_02.js

und liefert folgende Ausgabe:
 

  Rhino_02 - investigates the detection of data types

  testing type characteristics of a "Boolean" object
   - typeof(Boolean) = boolean
   - Boolean has no (intrinsic) superclass

  testing type characteristics of a "Number" object
   - typeof(Number) = number
   - Number has no (intrinsic) superclass

  testing type characteristics of a "String" object
   - typeof(String) = string
   - String has no (intrinsic) superclass

  testing type characteristics of a plain object
   - typeof(Object) = object
   - Object is an instance of Object
   - Prototype(s) of Object: Object
   - Object has a constructor

  testing type characteristics of an "Array" object
   - typeof(Array) = object
   - Array is an instance of Object, Array
   - Prototype(s) of Array: Object, Array
   - Array has a constructor

  testing type characteristics of a "Date" object
   - typeof(Date) = object
   - Date is an instance of Object, Date
   - Prototype(s) of Date: Object, Date
   - Date has a constructor

  testing type characteristics of a "Function" object
   - typeof(Function) = function
   - Function is an instance of Object, Function
   - Prototype(s) of Function: Object, Function
   - Function has a constructor
   - Function has a prototype

  testing type characteristics of an user-defined object
   - typeof(UserObject) = object
   - UserObject is an instance of Object, Function
   - Prototype(s) of UserObject: Object, Function
   - UserObject has a constructor
   - UserObject has a prototype

  testing type characteristics of a "null" object
   - typeof(null) = object
   - null has no (intrinsic) superclass

  testing type characteristics of an undefined object
   - typeof(undefined) = undefined
  error while evaluating file "Rhino_02.js"
  (reason: "Rhino$RhinoException: Rhino.evaluate: EvaluatorException while evaluating file "Rhino_02.js" (reason: "The undefined value has no properties.")")

Offensichtlich werden nur "primitive" Datentypen (boolean, number, string) sowie Funktionsobjekte unmittelbar erkannt - alle andere Datentypen sind aus Sicht von JavaScript nichts weiter als "Objekte". Interessant ist übrigens auch die Klassifizierung explizit "konstruierter" Objekte als Funktionsinstanzen (vermutlich, weil der verwendete Konstruktor ein Funktionsobjekt ist).

Und obwohl eigentlich auch "primitive" Datentypen einen impliziten Prototypen besitzen, wissen die Instanzen dieser Datentypen anscheinend nichts davon...

Bemerkenswert an der Ausgabe von Rhino_02 ist aber vor allem auch die Ausnahme, die bei der Untersuchung eines nicht-definierten Objektes geworfen wird - und die Tatsache, daß sich diese Ausnahme (zumindest unter Rhino) offenbar nicht abfangen läßt! In der (Programmier-)Praxis bedeutet dies, daß evtl. nicht-definierte Parameter einer Funktion möglichst frühzeitig erkannt und z.B. durch passende Vorgabewerte ersetzt werden müssen. Dies kann z.B. durch eine Konstruktion der Form

  if (typeof(<argument>) == "undefined") ...;

geschehen.

Quelltexte

Das hier vorgestellte Skript ist im Quelltext verfügbar:

Haftungsausschluß

Bitte beachten Sie auch den Haftungsausschluß des Autors!

http://www.Andreas-Rozek.de/Rhino/Acquainting/Rhino_02.html    (letzter Stand: 06.04.2002)