Christian: Verkettete Listen in Javascript

Hallo erstmal!

Ich hab folgendes Problem. Ich versuche eine einfach verkettete Liste zu programmieren und irgendwie merkt sich der browser nicht meine variable next.

Ich poste einmal den Source-Code

function Column(name) {
 this.name = name;
 this.next = null;

this.setName = function(name) {
  this.name = name;
 }

this.getName = function() {
  return this.name;
 }

this.setNext = function(next) {
  this.next = next;
 }

this.getNextName = function() {
  document.write(this.next.getName());
 }

this.getNext = function() {
  //document.write(next.getName();
  return this.next;
 }

this.hasNext = function() {
  if (this.next == null) return false;
  if (this.next != null) return true;
 }

}

Nun erstelle ich eine Instanz mit

column1 = new Column("erstes Element");
column2 = new Column("zweites Element");

columns = column1.setNext(column2);
document.write(columns.getNext().getName());

Nun sollte eigentlich der Browser "zweites Element" ausgeben. Tut er aber nicht :(. Vielleicht weiß jemand von euch die Lösung auf mein Problem :).

lg
Christian

  1. Hi,

    this.setNext = function(next) {
      this.next = next;
    }
    columns = column1.setNext(column2);
    document.write(columns.getNext().getName());

    was genau soll columns Deiner Ansicht nach hier enthalten, und welcher Code führt Deiner Meinung nach dazu?

    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,

      this.setNext = function(next) {
        this.next = next;
      }
      columns = column1.setNext(column2);
      document.write(columns.getNext().getName());

      was genau soll columns Deiner Ansicht nach hier enthalten, und welcher Code führt Deiner Meinung nach dazu?

      Cheatah

      Mein Ziel mit diesen Code ist es folgende Struktur zu etablieren:

      columns.name = "erstes Element"
      columns.next = column2
      columns.next.name = "zweites Element"
      columns.next.next = null

      Meiner Meinung nach müsste der Fehler sich in  this.setNext = function(next) befinden. Weil hier wird next an das Objekt übergeben.  Innerhalb von dieser function kann ich noch auf next und this.next zugreifen. Aber danach ist this.next plötzlich leer.
      Eigentlich müsste ich dieser function nicht das Objekt speichern sondern den Pointer auf das Objekt. Nun ist mir nicht wirklich bewusst wie man mit JavaScript Pointer schreibt oder ob das wie in Java gehandhabt wird.

      1. Hi,

        this.setNext = function(next) {
          this.next = next;
        }
        columns = column1.setNext(column2);
        Mein Ziel mit diesen Code ist es folgende Struktur zu etablieren:

        [...]

        Meiner Meinung nach müsste der Fehler sich in  this.setNext = function(next) befinden.

        ja. Du erwartest, dass Dir diese Methode irgendwas zurück gibt, was Du einer Variablen sinnvoll zuweisen kannst. Das tut sie aber nicht. Ergo: Lass sie das zurück liefern, was Du erwartest.

        Nun ist mir nicht wirklich bewusst wie man mit JavaScript Pointer schreibt oder ob das wie in Java gehandhabt wird.

        JavaScript arbeitet mit Referenzen - das genügt vollkommen. Das Handling an sich ist dem in Java sehr ähnlich.

        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. ja. Du erwartest, dass Dir diese Methode irgendwas zurück gibt, was Du einer Variablen sinnvoll zuweisen kannst. Das tut sie aber nicht. Ergo: Lass sie das zurück liefern, was Du erwartest.

          Die Methode setNext soll nichts zurückliefern. Sie speichert nur die übergebene Variable ins Objekt

          mit getNext soll dieser Wert wieder ausgelesen werden

          1. Hi,

            Die Methode setNext soll nichts zurückliefern.

            columns = column1.setNext(column2);

            Welchen Sinn hat dann diese Zuweisung?

            cu,
            Andreas

            --
            Warum nennt sich Andreas hier MudGuard?
            O o ostern ...
            Fachfragen unaufgefordert per E-Mail halte ich für unverschämt und werde entsprechende E-Mails nicht beantworten. Für Fachfragen ist das Forum da.
            1. Danke Andreas, das war mein fehler

              return this gehört noch in die funktion setNext

              1. Hallo,

                Also, ich würde nicht mit so vielen Methoden à la klassische Vererbung arbeiten. Mach' es doch einfach so:

                  
                function listItem(inList, itemName, previous, next) {  
                 return {  
                    parentObj: inList,  
                    itemName: itemName,  
                    previous: previous,  
                    next: next };  
                }  
                  
                //Nun erstelle Instanzen mit z.B.:  
                  
                table1 = new listItem(this, 'Tabelle1', null, null);  
                table2 = table1.next = = new listItem(this, 'Tabelle2', table1, null);  
                table3 = table1.next = = new listItem(this, 'Tabelle3', table2, null);  
                // usw.  
                  
                row1 = new listItem(table1, 'Reihe1', null, null);  
                row2 = row1.next = new listItem(table1, 'Reihe2', row1, null);  
                row3 = row2.next = new listItem(table1, 'Reihe3', row2, null);  
                // usw.  
                  
                col1 = new listItem(table1, 'Spalte1', null, null);  
                col2 = col1.next = new listItem(table1, 'Spalte2', col1, null);  
                col3 = col2.next = new listItem(table1, 'Spalte3', col2, null);  
                // usw.  
                  
                document.write(col2.next.itemName);  
                  
                
                

                Gruß, Don P

                1. Hallo,

                  Sorry, Typo, es muss natürlich so lauten:

                    
                  function listItem(inList, itemName, previous, next) {  
                    
                    return {  
                      parentObj: inList,  
                      itemName: itemName,  
                      previous: previous,  
                      next: next };  
                  }  
                    
                  table1 = new listItem(this, 'Tabelle1', null, null);  
                  table2 = table1.next = new listItem(this, 'Tabelle2', table1, null);  
                  table3 = table1.next = new listItem(this, 'Tabelle3', table2, null);  
                  // usw.  
                    
                  row1 = new listItem(table1, 'Reihe1', null, null);  
                  row2 = row1.next = new listItem(table1, 'Reihe2', row1, null);  
                  row3 = row2.next = new listItem(table1, 'Reihe3', row2, null);  
                  // usw.  
                    
                  col1 = new listItem(table1, 'Spalte1', null, null);  
                  col2 = col1.next = new listItem(table1, 'Spalte2', col1, null);  
                  col3 = col2.next = new listItem(table1, 'Spalte3', col2, null);  
                  // usw.  
                    
                  document.write(col2.next.itemName);
                  

                  Gruß, Don P

                  --
                  sh:( fo:) ch:? rl:( br:] n4:~ ie:% mo:? va:{ js:) de:/ zu:] fl:( ss:| ls:&
                2. Hallo,

                  Eigentlich braucht man auch keinen new-Operator. Folgender Code tut's auch:

                    
                  function listItem(inList, itemName, previous, next) {  
                    
                    return {  
                    
                      parentObj: inList,  
                      itemName: itemName,  
                      previous: previous,  
                      next: next };  
                  }  
                    
                  table1 = listItem(this, 'Tabelle1', null, null);  
                  table2 = table1.next = listItem(this, 'Tabelle2', table1, null);  
                  table3 = table1.next = listItem(this, 'Tabelle3', table2, null);  
                  // usw.  
                    
                  row1 = new listItem(table1, 'Reihe1', null, null);  
                  row2 = row1.next = listItem(table1, 'Reihe2', row1, null);  
                  row3 = row2.next = listItem(table1, 'Reihe3', row2, null);  
                  // usw.  
                    
                  col1 = new listItem(table1, 'Spalte1', null, null);  
                  col2 = col1.next = listItem(table1, 'Spalte2', col1, null);  
                  col3 = col2.next = listItem(table1, 'Spalte3', col2, null);  
                  // usw.  
                    
                  document.write(col2.next.itemName);
                  

                  Gruß, Don P

  2. [latex]Moin![/latex]

    Ich hab folgendes Problem. Ich versuche eine einfach verkettete Liste zu programmieren und irgendwie merkt sich der browser nicht meine variable next.

    Er merkt sich vor allem nicht dein this, d.h. wenn du nach den Initialisierung eine der Funktionen aufrufst, ist this nicht mehr das gewünschte Objekt.

    Du mußt das Objekt in einer Variablen speichern und dann in den Funktionen, die von Außerhalb aufrufbar sind, diese Variable benutzen:

    function Column(name) {  
      var foo = this;  
      
      //weiterer Code  
      
      this.getName = function() {  
        return foo.name;  
      }  
      
      //weiterer Code  
      
    }  
    
    

    Dein Suchbegriff lautet Closures.

    Cü,

    Kai

    --
    een eigen huis, een plek onder de zon
    en altijd iemand in de buurt die van me houden kon
    toch wou ik dat ik net iets vaker, iets vaker simpelweg gelukkig was
    ie:{ fl:( br:< va:) ls:? fo:| rl:? n4:° ss:{ de:] js:| ch:? mo:| zu:|]
    1. Dein Suchbegriff lautet Closures.

      In dem Falle nicht. this ist hier durchaus richtig.

      Struppi.

    2. Hallo,

      function Column(name) {

      var foo = this;

      //weiterer Code

      this.getName = function() {
          return foo.name;
        }

      //weiterer Code

      }

      
      >   
      > Dein Suchbegriff lautet Closures.  
        
      Öffentliche Methoden werden immer in der Form instanz.öffentlicheMethode() aufgerufen, damit werden sie immer im Kontext der Instanz aufgerufen, damit zeigt this immer auf die Instanz, damit braucht man keine Closures und auch kein Kontext-Binding in diesem Fall.  
        
      (Außerdem war der Witz im Code des OP ja, dass er eine \*andere\* Instanz ansprechen will, die unter this.next gespeichert ist.)  
        
      Bei privaten Methoden oder Methoden, die als Event-Handler wirken oder verzögert aufgerufen werden, ist das was anderes.  
        
      Closures sind ziemlich mächtig und kommen häufig vor, aber ich hab das Gefühl, dass, nachdem sie hier im Selfraum bekannter geworden sind, alle denken, alles in JavaScript bestünde aus Closures. ;)  
        
      Mathias
      
      -- 
      [SELFHTML aktuell Weblog](http://aktuell.de.selfhtml.org/weblog/)
      
  3. Ich hab folgendes Problem. Ich versuche eine einfach verkettete Liste zu programmieren und irgendwie merkt sich der browser nicht meine variable next.

    Mal abgesehen vom Sinn (meiner Meinung sind verkette Listen in JS nicht nötig, was bieten sie, was Arrays nicht haben?), ist deine Umsetzung auch seltsam, da du nur das, was klassischerweise Node genannt wird, umsetzt. Wo ist die Liste?
    dort sollten next (und evtl. previous) gesetzt werden, z.b. in einer Funktion add(node).

    Hier mal ein kurzes Beispiel:

    function Node(name) {  
     this.name = name;  
     this.next = null;  
     this.getName = function() { return this.name;}  
    }  
      
    function List() {  
     var first = null;  
     var last = null;  
     this.add = function( node) {  
      
      if(!first)  first = last = node;  
      else last.next = node;  
      
      last = node;  
     }  
     this.show = function() {  
      var t = 'List:\n';  
      var akt = first;  
      while( akt ) {  
       t += akt.name + '\n';  
       akt = akt.next;  
      }  
      return t;  
     }  
    }  
    var list = new List();  
    list.add( new Node('eintrag: 1'));  
    list.add( new Node('eintrag: 2'));  
    list.add( new Node('eintrag: 3'));  
      
    alert( list.show() );  
    
    

    Struppi.

    1. Danke für den Einblick in deinen Code. Was ich dort nicht ganz verstehe wofür last in List verwendet wird.

      Leider weiß ich noch immer nicht die Lösung zu meinen Problem. Um das Problem verständlicher zu machen möchte ich erklären was mit diesem Code-Schnipsel umgesetzt werden soll.

      Ich hatte die Idee das ich eine Tabelle erstelle die beim vertauschen von Zeilen und beim vertauschen von Spalten die innere Ordnung behält. Mein Ansatz sieht folgender Weise aus:

      Die Tabelle wird so gespeichert

      columnA --> columnB --> columnC
                 ^           ^          ^
                 |           |          |
      row1 --> cellA1 --> cellB1 -->  cellC1
       |
       v
      row2 --> ...
       |
       v
      row3 --> ...

      wenn ich nun zwei zeilen vertausche brauch ich nur die reihenfolge der rows zu ändern

      columnA --> columnB --> columnC
                 ^           ^          ^
                 |           |          |
      row2 --> cellA2 --> cellB2 -->  cellC2
       |
       v
      row1 --> ...
       |
       v
      row3 --> ...

      wenn ich nun zwei spalten vertauschen ist dies schon komplizierter

      columnB --> columnA --> columnC

      row1 --> cellA1 --> cellB1 -->  cellC1
       |
       v
      row2 --> ...
       |
       v
      row3 --> ...

      hier zeigt cellA1 auf columnA und cellB1 auf columnB usw. Aber die Reihenfolge der cells ist nun nicht mehr ident mit der der columns. Um dieses Problem zu lösen müssen die columns auf die cells zurückzeigen.

      Die Ausgabe der Tabelle funktioniert dann so:
      Man geht jede Reihe durch
        innerhalb der Reihe geht man jede Zelle ab
          jede einzelne Zelle verweist schon grundsätzlich auf die ihre
          zugehörige Spalte. Nun muss die Spalte nur mehr auf die Zelle
          zurückverweisen.
        jetzt geht man die Spalten der Reihenfolge nach ab und schaut auf
        welche Zelle sie zurückverweisen und gibt sie wieder aus.

      => Spalten und Zeilenumformungen kann man so einfach durchführen indem man Zeilen oder Spalten vertauscht ohne die ihnen zugehörigen Zellen zu vertauschen.

      1. Danke für den Einblick in deinen Code. Was ich dort nicht ganz verstehe wofür last in List verwendet wird.

        Naja, du musst ja Wissen wo du ein neues Element in der Liste einfügen willst, i.d.R. bei einer einfach verketten Liste ist dies am Ende, oder?

        Ich hatte die Idee das ich eine Tabelle erstelle die beim vertauschen von Zeilen und beim vertauschen von Spalten die innere Ordnung behält. Mein Ansatz sieht folgender Weise aus:

        Dann hast du ein zweidimensonales Array, das wird sich wohl nicht mit in einer verketteten Liste so ohne weiteres umsetzen lassen. Zumindest wüßte ich nicht wie.

        Struppi.

    2. Hallo,

      Mal abgesehen vom Sinn (meiner Meinung sind verkette Listen in JS nicht nötig, was bieten sie, was Arrays nicht haben?)

      Man kommt so von einem Object, das man einzeln hat, zum vorigen und nächsten, ohne den Array durchlaufen zu müssen und die Stelle zu finden, wo das Object gespeichert ist. Alternativ könnte man natürlich die Arrayposition am Object speichern, aber da ist es doch komfortabler, gleich eine Referenz auf vorige und nächste Object anzulegen.

      Wenn ich z.B. Controls baue, die irgendwie eine Listenstruktur umsetzen, dann kann ich natürlich an einem übergeordneten HTML-Element oder an einem globalen Objekt einen Array speichern, der alle relevanten Unterelemente enthält, aber ich kann auch einfach die Unterelemente aufeinander verweisen lassen.

      Mathias