Michael H.: JavaScript: Objekte und Kontext: Unlogischer Fehler

Hallo Leute,

Ich werde grade wahnsinnig. Ich habe mir in JS ein Objekt namens "tag" angelegt und würde es gerne benutzen. Solange ich das im regulären, nicht gekapselten Scriptcode verwende ist alles ok.
Also z.B..

<script type="text/javascript">
var tag = new tag();
console.log(tag);
</script>

liefert brav: "object"

ABER: sobald ich das Gleiche in einer Funktion machen will (schließlich will ich ja nicht alles gleich machen), wirft er mir einen Fehler.
Beispiel:

<script type="text/javascript">
function test_tag()
{
  var tag = new tag();
  console.log(tag);
}
test_tag();
</script>

das liefert mir die Fehlermeldung: "tag is not a constructor". Aber es ist doch der gleiche Code verdammt! Zur Sicherheit hier noch mein Klassencode:

function tag()
{
 this.ID = -1;
 this.tag = '';
 this.create = function(tagtext){ };
 this.load = function(tag_ID) { };
 return true;
}

Kann mir irgendwer helfen und erklären was hier abgeht?

DANKE!

Michael

  1. var tag = new tag();

    Du kannst nicht wahllos die Namen vergeben.

    Schau dir das mal an:

    function test_tag()  
    {  
     alert(tag);  
    }  
    function test_tag_2()  
    {  
     alert(tag);  
     var tag;  
    }  
    test_tag();  
    test_tag_2();  
    
    

    Mit var tag überschreibst du also lokal die Funktion.

    Struppi.

    1. var tag = new tag();

      Du kannst nicht wahllos die Namen vergeben.
      Mit var tag überschreibst du also lokal die Funktion.

      Das meinte Cheetah auch, aber das müsste doch in beiden Fällen zu einem Fehler führen oder nicht? Es geht aber nur dann nicht, wenn ich den Code in einer Funktion kapsle, im Scriptcode geht das...

      Danke erstmal, aber das löst mein Problem noch nicht.

      1. var tag = new tag();

        Du kannst nicht wahllos die Namen vergeben.
        Mit var tag überschreibst du also lokal die Funktion.

        Das meinte Cheetah auch, aber das müsste doch in beiden Fällen zu einem Fehler führen oder nicht? Es geht aber nur dann nicht, wenn ich den Code in einer Funktion kapsle, im Scriptcode geht das...

        Weil du nur dort eine lokale Variabel anlegst, dieser wird beim erzuegen des Funktionsrumpf angelegt, die globale in dem Moment wo sie im Quelltext steht, deshalb funktioniert z.b. auch nicht:

        var tag = new tag();  
        var tag_2 = new tag();  
        
        

        Danke erstmal, aber das löst mein Problem noch nicht.

        Wieso nicht? Benenne die Variabel um und alles ist perfekt. Du kannst in JS nicht wahllos Namen vergeben - hab ich aber schon gesagt

        Struppi.

        1. Das meinte Cheetah auch, aber das müsste doch in beiden Fällen zu einem Fehler führen oder nicht? Es geht aber nur dann nicht, wenn ich den Code in einer Funktion kapsle, im Scriptcode geht das...

          Weil du nur dort eine lokale Variabel anlegst, dieser wird beim erzuegen des Funktionsrumpf angelegt, die globale in dem Moment wo sie im Quelltext steht, deshalb funktioniert z.b. auch nicht:

          var tag = new tag();

          var tag_2 = new tag();

            
          Ok, dann hab ich das endlich verstanden!  
            
          
          > > Danke erstmal, aber das löst mein Problem noch nicht.  
          >   
          > Wieso nicht? Benenne die Variabel um und alles ist perfekt.  
            
          Hab ich auch gemacht und es löst das direkte Problem. Ich wollte das \_verstehen\_ warum es auftritt und warum nicht überall, damit ich das nächste Mal gleich selbst denken kann :-)  
            
          Danke!  
            
          Michael
          
  2. Hi,

    var tag = new tag();

    hältst Du es für sinnvoll, den Konstructor durch seine eigene Instanziierung zu überschreiben?

    das liefert mir die Fehlermeldung: "tag is not a constructor". Aber es ist doch der gleiche Code verdammt! Zur Sicherheit hier noch mein Klassencode:

    Ja, nur dass Du vor der Ausführung eine Variable erzeugst, die zunächst nichts enthält, und dann bei der Ausführung instanziiert wird. Genauso gut kannst Du "new undefined()" schreiben. Im globalen Kontext existierte "tag" bereits und blieb bei der Deklaration somit erhalten.

    function tag()

    Klassen (bzw. Konstruktoren) beginnt man per Konvention übrigens mit Großbuchstaben.

    Cheatah

    --
    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: No
    X-Please-Search-Archive-First: Absolutely Yes
    1. Hi,

      var tag = new tag();

      hältst Du es für sinnvoll, den Konstructor durch seine eigene Instanziierung zu überschreiben?

      Oh mann, das ist doch nicht wahr. Das Ding kann nicht zwischen Variable und Funktion unterscheiden? Na ja, muss ich eben dran denken. Logisch ist es aber trotzdem nicht, warum es außerhalb der Funktion klappt und innerhalb nicht. Müsste doch beides schiefgehen nach deiner Erklärung oder nicht???

      function tag()

      Klassen (bzw. Konstruktoren) beginnt man per Konvention übrigens mit Großbuchstaben.

      ok ok, bin eben faul :-)Erstmal danke, aber richtig beantwortet wurde es nicht...

      1. Update: ihr hattet recht, das Problem ist damit gelöst.
        Aber so ganz erklären kann ich mir den vorher funktionierenden Code nicht...

        Anyway: DANKE!!!

      2. Hi,

        Oh mann, das ist doch nicht wahr. Das Ding kann nicht zwischen Variable und Funktion unterscheiden?

        nein, JavaScript kann nicht zwischen Eigenschaften des window-Objektes und Eigenschaften des window-Objektes unterscheiden.

        Logisch ist es aber trotzdem nicht, warum es außerhalb der Funktion klappt und innerhalb nicht.

        Doch, weil a) Variablen hier nicht mehr Eigenschaften des window-Objektes sind und b) vor der Ausführung des Codes erstellt werden. Du greifst somit nicht mehr auf die globale tag()-Funktion zu, sondern auf die lokale Variable - die leer ist (also undefined enthält).

        Müsste doch beides schiefgehen nach deiner Erklärung oder nicht???

        Nein. Der Unterschied ist, dass es einmal im Kontext etwas gibt, was sich instanziieren lässt, und das andere mal nicht. Somit erzeugst Du einmal die Variable mit etwas Existierendem und einmal mit undefined.

        Cheatah

        --
        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: No
        X-Please-Search-Archive-First: Absolutely Yes
  3. Moin.

    Das Problem wurde ja bereits geklärt. Ich bin übrigens auch schon darüber gestolpert, denn so abwegig ist Michaels Annahme nicht.

    JavaScript interpretiert offensichtlich

    var name = value;

    genauso wie

    var name;
        name = value;

    und setzt dies in folgenden Pseudo-Code um (der so in JavaScript nicht möglich ist, da auf das Kontext-Objekt nicht zugegriffen werden kann):

    context.createVar('name');
        context.setVar('name', value);

    Ebenso wäre aber auch denkbar,

    var name = value;

    als

    context.createAndSetVar('name', value);

    und entsprechend

    var name;
        name = value;

    als

    context.createAndSetVar('name', undefined);
        context.setVar('name', value);

    zu interpretieren, was unterschiedliche Ergebnisse zur Folge hätte, wenn value selbst auf eine Variable names 'name' zugreift, da ja Argumente in JavaScript strikt, d.h. vor Funktionsaufruf evaluiert werden.

    Christoph

    1. Hallo,

      Ebenso wäre aber auch denkbar, (...)

      var name;
          name = value;

      als

      context.createAndSetVar('name', undefined);
          context.setVar('name', value);

      zu interpretieren

      Und das ist auch der Fall in Funktionen.
      http://bclary.com/log/2004/11/07/#a-10.1.3

      window.bla = "wert";  
      function f () {  
         alert(bla);  
         var bla;  
      }  
      f();
      

      Beim Ausführen der Funktion passiert, bevor überhaupt der Code im Funktionskörper ausgeführt wird, folgendes:
      1. Die übergebenen Parameter werden ins internen Variablenobjekt kopiert.
      2. Alle Funktionsdeklarationen innerhalb des Funktionskörpers erzeugen Eigenschaften beim Variablenobjekt.
      3. Alle Variable Statements (das sind die var bla = ...; und var bla;) erzeugen Eigenschaften beim Variablenobjekt mit dem Wert undefined.

      Dann wird erst der Code im Funktionskörper ausgeführt. Wenn also die Funktion startet, ist die Variable bla im Beispiel schon existent und hat den Wert undefined. Notiere ich bla, wird zuerst beim Variablenobjekt der Funktion gesucht, dort wird eine entsprechende Variable gefunden, also wird gar nicht weiter in der Scope-Chain gesucht.

      Ich kann also nicht schreiben var bla = bla + " blub"; bzw. würde halt "undefined blub" rauskommen. Will ich auf die globale Variable zugreifen, muss ich explizit window.bla notieren.

      Mathias

      1. Hallo,

        1. Alle Funktionsdeklarationen innerhalb des Funktionskörpers erzeugen Eigenschaften beim Variablenobjekt.

        Der Punkt ist sogar sehr praktisch:

        function f () {  
           inner();  
           function inner () { ... }  
        }  
        f();
        

        Hier spielt die Reihenfolge keine Rolle.

        Allerdings spielt sie eine Rolle, wenn man Funktionsausdrücken notiert:

        function K () {  
           var inner = function () { ... };  
           this.method = function () { ... };  
          
           inner();  
           this.method();  
        }  
        new K();
        

        Anders herum ginge es nicht. Die Regel gilt halt nur für Funktionsdeklarationen.

        Mathias