Felix Riesterer: Konstruktorfunktion: return false?

Liebe Spezialisten,

ich hatte mir bisher eingebildet, ich könnte in einer Konstruktorfunktion steuern, ob ein Objekt, oder der Wert false zurückgegeben wird.

myObj = function (param) {  
    this.name = "myObject";  
  
    if (!param) return false; // ohne param kein Objekt!  
}  
  
alert("mit param: "+ new myObj("dummy");  
alert("ohne param: "+ new myObj();

Hintergrund: Ich möchte bereits im Konstruktor prüfen, ob ein Objekt dieser Art mit diesen Parametern angelegt werden kann/darf, um im negativen Falle vom Konstruktor selbst anstatt des erwarteten Objektes eben false zurückgeben zu lassen. ABER: Ich erhalte in _jedem_ Fall ein Objekt zurück. Daher nun meine Frage.

Kann man überhaupt in einem Konstruktor darauf Einfluss nehmen, ob ein Objekt oder "ein Fehlercode" zurückgegeben wird, oder wird _immer_ ein Objekt zurückgegeben, weil das anscheinend die Logik eines Konstruktors bedingt?

Meinetwegen nehme ich auch null anstatt false für ein negativ-Ergebnis...

Liebe Grüße,

Felix Riesterer.

--
ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
  1. Wenn kein String angegeben ist, bekommst Du ein Objekt mit dem Inhalt "false" zurück, ansonsten eben das Objekt mit dem Inhalt, den Du darin definierst.

    Das Konzept "Alles ist ein Objekt" ist in dieser Hinsicht konsequent durchgesetzt.

    Gruß, LX

    --
    X-Self-Code: sh:( fo:) ch:~ rl:° br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
    X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
    X-Will-Answer-Email: Unusual
    X-Please-Search-Archive-First: Absolutely Yes
    1. Lieber LX,

      Wenn kein String angegeben ist, bekommst Du ein Objekt mit dem Inhalt "false" zurück

      bedeutet das, der Rückgabewert ist vom Typ "object", anstatt vom Typ "boolean"? Das wäre erstmal interessant! Das muss ich ausprobieren, denn dann könnte ich mit return null tatsächlich das erreichen, was ich vorhatte.

      Was mir allerdings nicht so klar ist: "Objekt mit dem Inhalt 'false'". Das müsste ja ein Objekt mit der Eigenschaft "false" sein, die dann irgendwie (k)einen Wert hat. Wie gesagt, ich schau mir das unter diesem Aspekt nocheinmal genauer an.

      Liebe Grüße,

      Felix Riesterer.

      --
      ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
      1. Hallo,

        dann könnte ich mit return null tatsächlich das erreichen, was ich vorhatte.

        Nein, Du darfst dich nicht von der Rückgabe des typeof-Operators narren lassen. null ist ein Primitive vom Typ Null. Und dieser interne Typ zählt.

        (Um deine Frage vorweg zu nehmen: Ein null-Object gibt es nicht.)

        Das müsste ja ein Objekt mit der Eigenschaft "false" sein, die dann irgendwie (k)einen Wert hat.

        Nein, siehe mein Posting.

        Mathias

  2. Hallo,

    Kann man überhaupt in einem Konstruktor darauf Einfluss nehmen, ob ein Objekt oder "ein Fehlercode" zurückgegeben wird, oder wird _immer_ ein Objekt zurückgegeben, weil das anscheinend die Logik eines Konstruktors bedingt?

    ECMAScript:
    "7. If Type(Result(6)) [Rückgabewert der Funktion] is Object then return Result(6).
    [andernfalls]
    8. Return Result(1) [das Instanzobjekt]."

    Es muss also immer ein Objekt zurückgegeben werden.
    Das kann also auch ein Boolean-Objekt sein: new Boolean(false)
    Mit einem Boolean-Primitive wirst du aber kein Glück haben.

    Mathias

    1. Lieber molily,

      ECMAScript:
      "7. If Type(Result(6)) [Rückgabewert der Funktion] is Object then return Result(6).
      [andernfalls]
      8. Return Result(1) [das Instanzobjekt]."

      oh Gott, was man alles wissen (oder nachlesen) könnte... unglaublich.

      Es muss also immer ein Objekt zurückgegeben werden.

      Da kann ich Dir noch folgen.

      Das kann also auch ein Boolean-Objekt sein: new Boolean(false)

      Da kann ich Dir auch noch folgen.

      Mit einem Boolean-Primitive wirst du aber kein Glück haben.

      Das kapiere ich (noch) nicht. Muss ich also anstatt return false eher das hier schreiben? return new Boolean(false);

      Liebe Grüße,

      Felix Riesterer.

      --
      ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
      1. Hallo,

        Muss ich also anstatt return false eher das hier schreiben? return new Boolean(false);

        Ja.

        Mathias

        1. Lieber molily,

          Muss ich also anstatt return false eher das hier schreiben? return new Boolean(false);

          Ja.

          ich danke Dir und werde das weiter prüfen - mal sehen, ob sich weitere Fragen ergeben. Aber wenn, dann erst morgen. Gute Nacht!

          Liebe Grüße,

          Felix Riesterer.

          --
          ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
  3. Hallo,

    Kann man überhaupt in einem Konstruktor darauf Einfluss nehmen, ob ein Objekt oder "ein Fehlercode" zurückgegeben wird, oder wird _immer_ ein Objekt zurückgegeben

    Die Begrenzung auf Objects macht es wenig sinnvoll, auf diese Weise mit dem aufrufenden Programmteil zu kommunizieren. Angenommen, man gibt ein Boolean-Objekt zurück, so kann man zwar if (instanz == false) prüfen. Wenn man das aber lässt, was wahrscheinlich ist, wenn man schon den Konstruktor falsch aufruft, dann bringt das eher wenig. Man wird sich nur wundern, warum das zurückgegebene Objekt nicht die Member hat, die man erwartet.

    Ich würde in so einem Falle der Fehlbedienung einfach kurzen Prozess machen:

    if (!param) {  
       throw "Konstuktor myObj wurde fehlerhaft aufgerufen: Der obligatorische Parameter xyz fehlt.";  
    }
    

    Besser an einer Stelle mit einer hilfreichen Fehlermeldung das Programm beenden, als dass sich später jemand fragt, warum das Objekt keine Eigenschaften und Methoden hat. (Niemand bekommt heraus, dass es ein Boolean-Objekt ist.)

    Mathias

    1. Lieber molily,

      danke für Deine sehr hilfreichen Erläuterungen.

      Ich würde in so einem Falle der Fehlbedienung einfach kurzen Prozess machen:

      if (!param) {

      throw "Konstuktor myObj wurde fehlerhaft aufgerufen: Der obligatorische Parameter xyz fehlt.";
      }

        
      Das ist für mich sehr aufschlussreich! Trotzdem möchte ich eine Fehlbedienung nicht nur dahingehend prüfen, ob ein bestimmter Parameter übergeben wurde, oder ob nicht. Ich möchte mehrere Bedingungen prüfen, die eventuell zu einer "Verweigerung" eines entsprechenden Objektes führen sollen. Es soll in mehreren Fällen vermieden werden, dass ein gültiges Objekt zurückgegeben wird. Ein Script-Abbruch soll unter garkeinen Umständen erfolgen - daher scheidet `throw`{:.language-javascript} schonmal definitiv aus.  
        
      Ich arbeite natürlich gerade an meinem Artikel weiter, wobei ich über diesen Umstand gestolpert bin, als ich die Prüfungen zu Beginn [meines Konstruktors](http://aktuell.de.selfhtml.org/artikel/review/fader-framework/index.htm#konstruktor_angepasst) einmal unter ungünstigen Bedingungen testen wollte.  
        
      Im Moment versuche ich das so zu lösen, indem das Objekt schon während seiner Erstellung sich selbst überprüft, um dann die diversen Memberfunktionen mit einer `function () { return false; }`{:.language-javascript} zu versehen, und das Objekt damit "unschädlich" zu machen.  
        
      Gibt es da vielleicht etwas besseres als meine bisherige Methode?  
        
      Liebe Grüße,  
        
      Felix Riesterer.
      
      -- 
      ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
      
      1. Hello,

        Gibt es da vielleicht etwas besseres als meine bisherige Methode?

        würde mich ebenfalls interessieren. Ich halte die Rückgabe von false nämlich (als eher Java-geprägter Programmierer) für äußerst unglücklich. Ein Konstruktor ist ein Konstruktor, er hat ein Objekt zu liefern. Man sollte einen Konstruktor nicht falsch bedienen können. Wenn man Angst um falsche Aufrufe hat böte sich ein Factory-Pattern an, aber kann JavaScript sowas? Hmh, offenbar ja.

        MfG
        Rouven

        --
        -------------------
        sh:| fo:} ch:? rl:( br:& n4:{ ie:| mo:} va:) js:| de:] zu:| fl:( ss:) ls:& (SelfCode)
        Inter Arma Enim Silent Leges  --  Cicero
      2. n'abend,

        Lieber molily,

        danke für Deine sehr hilfreichen Erläuterungen.

        Ich würde in so einem Falle der Fehlbedienung einfach kurzen Prozess machen:

        if (!param) {

        throw "Konstuktor myObj wurde fehlerhaft aufgerufen: Der obligatorische Parameter xyz fehlt.";
        }

        
        >   
        > Das ist für mich sehr aufschlussreich! Trotzdem möchte ich eine Fehlbedienung nicht nur dahingehend prüfen, ob ein bestimmter Parameter übergeben wurde, oder ob nicht. Ich möchte mehrere Bedingungen prüfen, die eventuell zu einer "Verweigerung" eines entsprechenden Objektes führen sollen. Es soll in mehreren Fällen vermieden werden, dass ein gültiges Objekt zurückgegeben wird. Ein Script-Abbruch soll unter garkeinen Umständen erfolgen - daher scheidet `throw`{:.language-javascript} schonmal definitiv aus.  
          
        Exception-Handling in Javascript ist (mittlerweile) durchaus erwünscht. Durch das Werfen einer Exception bricht dein Script nicht automatisch ab - du kannst dich ja schließlich um die Fehlerbehandlung kümmern. Ob du nun auf false (oder sonst was) prüfst, oder dir try-catch zu Nutze machst, dürfte dabei doch relativ egal sein? Mit Exceptions hast du sogar die Möglichkeit viel detailliertere Infos über den Fehlerfall zu erfahren.  
          
        [Das erste beste auffindbare Exception-Tutorial](http://wiki.ajax-community.de/tutorial:exception)  
          
        weiterhin schönen abend...
        
        -- 
        #selfhtml hat ein Forum?  
          
        sh:( fo:# ch:# rl:| br:> n4:& ie:{ mo:} va:) de:] zu:} fl:( ss:? ls:[ js:|
        
  4. Die Lösung, dass ein false-Wert auch als Boolean-Objekt übermittelt werden kann, war ein Detail, das mir als "interessierter Laie" so nicht klar war. Aber genau damit kann ich in meinem Projekt eine Prüfung vornehmen, die meinem Konstruktor die Möglichkeit gibt, ein passendes Objekt, oder eben "false" (als Boolean-Objekt) zurückzuliefern.

    Eine Fehlerbehandlung ist in meinem Falle nur darauf zu begrenzen, dass eben das passende Objekt zurückgeliefert wird - mehr nicht.

    Interessant für mich waren folgende Umstände, die mir sehr weitergeholfen haben:

    alert(new Boolean(false)); // gibt "false" aus -> Wert des Objektes  
      
    if (new Boolean(false)) { alert("true!") } // gibt "true" aus -> Objekt selbst wird als "true" interpretiert  
      
    // ergibt "false" -> Wert des Objektes  
    if (new Boolean(false) != false) {  
        alert("true");  
    } else {  
        alert("false");  
    }  
      
    // ergibt "true" -> Typ des Wertes des Objektes ist eben kein primitive  
    if (new Boolean(false) !== false) {  
        alert("true");  
    } else {  
        alert("false");  
    }
    

    Vielen Dank an alle, die mir hier wertvollen Hinweise gegeben haben! Auch wenn ich keine "echte" Fehlerbehandlung vor hatte, sind diese Ideen mit throw auch wieder etwas, das ich neu dazugelernt habe, und das ich vielleicht einmal später gebrauchen kann.

    Liebe Grüße,

    Felix Riesterer.

    --
    ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
    1. Hallo,

      Mal zum Verständnis die interne Auflösungen der Expressions:

      alert(new Boolean(false)); // gibt "false" aus -> Wert des Objektes

      ⇒ (new Boolean(false)).toString()
      ⇒ "false"

      if (new Boolean(false)) { alert("true!") } // gibt "true" aus -> Objekt selbst wird als "true" interpretiert

      ⇒ Boolean(new Boolean(false)))

      Umwandlung in Boolean gemäß ToBoolean
      Input Type ist Object, also

      ⇒ true

      // ergibt "false" -> Wert des Objektes
      if (new Boolean(false) != false) {

      Hier wird das rechte false gemäß dem Abstract Equality Comparison Algorithm in einen Number-Wert umgewandelt:

      ⇒ new Boolean(false) == 0

      Dann wird das Boolean-Objekt in einen Primitive umgewandelt. Das erfolgt über den DefaultValue mit dem Hint Number. Darin wird die Methode valueOf() aufgerufen. Und die gibt den Primitive Value false zurück. D.h.

      ⇒ (new Boolean(false)).valueOf() == 0
      ⇒ false == 0

      Damit sind wir wieder beim Abstract Equality Dingsbums, woraufhin wieder in Number umgewandelt wird:

      ⇒ 0 == 0
      ⇒ true

      Diese valueOf-Methode sollte man sich ohnehin mal merken, die haben alle Objekte, zu denen auch Primitive-Typen existieren.

      // ergibt "true" -> Typ des Wertes des Objektes ist eben kein primitive
      if (new Boolean(false) !== false) {

      ⇒ !(new Boolean(false) === false)

      Beim Strict Equality Comparison Algorithm werden zuerst die Typen verglichen. Es steht Object versus Boolean, somit sind die Typen ungleich, ergo

      ⇒ !(false)
      ⇒ true

      Mathias