Markus**: Prototyping Problem

Hallo Forum,

ich habe ein Problem mit JavaScript OO, es äußert sich in der folgenden Methode, bzw, bei deren Aufruf:

var t = new vehicle;  
t.Route_name("Test"); //Zeile 122  

hier gibt firefox die Meldung: //Fehler: uncaught exception: [Exception... "Illegal operation on WrappedNative prototype object"  nsresult: "0x8057000c (NS_ERROR_XPC_BAD_OP_ON_WN_PROTO)"  location: "JS frame :: file:///C:/bin/htdocs/kals.de/bus/scheduler/test.html :: <TOP_LEVEL> :: line 122"  data: no]" aus.//
Die dazugehörige Methode:

vehicle.prototype.Route_name = function(value) {  
	if (value != null) {  
		this.route_arr.push(value);  
		this.destination = value;  
		}  
	else  
		{  
		var temp = this.route_arr.shift();  
		this.route_arr.push(temp);  
		return temp;  
		}  
}

Was mach ich falsch?

Cheers, Markus**!

  1. Bei diesem Code fehlt mir, wie vehicle aufgebaut ist. Ist route_arr prototypisch oder eine in der Initialisierung gesetzte Eigenschaft?

    Bitte schicke uns auch den restlichen Code, damit wir das im Kontext betrachten können. Ansonsten würde ich an Deiner Stelle mal nachsehen, ob "this.route_arr" tatsächlich instanceof Array ist.

    Gruß, LX

    --
    RFC 5984, Satz 7 (Security Considerations) (...) Terroristische Organisationen könnten die "Schlechte Nachrichten verbreiten sich schneller"-Schwachstelle aus RFC 1216 ausnutzen.
    1. Bei diesem Code fehlt mir, wie vehicle aufgebaut ist. Ist route_arr prototypisch oder eine in der Initialisierung gesetzte Eigenschaft?

      LX, danke für die schnelle Antwort,
      hier mehr code:

        
        
      function vehicle(id) {  
      	this.id = id;  
      	this.route_arr = new Array;  
      	this.date = "";  
      	this.company = "";  
      	this.company_name = "";  
      	this.gate = "";  
      	this.status = "";  
      	this.changed = "";  
      	this.departure_time = "";  
      	this.destination = "";  
      }  
        
      vehicle.prototype = document.createElement("div");  
        
      vehicle.prototype.Route_name = function(value) {  
       if (value != null) {  
      	this.route_arr.push(value);  
      	this.destination = value;  
      	}  
      	else {  
      	var temp = this.route_arr.shift();  
      	this.route_arr.push(temp);  
      	return temp;  
      	}  
      }  
        
      vehicle.prototype.GetDiv = function() {  
      	this.style.width = "30px";  
      	this.style.height = "10px";  
      	this.style.border = "1px solid #bfbfbf";  
      	this.appendChild(document.createTextNode("Test"));  
      	return this;  
      }  
        
      var t = new vehicle(1);  
        
      t.departure_time = "03:15";  
      t.company = "ABCZ-OB";  
      t.company_name = "Test";  
      t.Route_name("Test1");  
      t.Route_name("Test2");  
      t.gate = "10";  
      t.status = "1";  
      t.changed = "0";
      

      Gruß, Markus**

      1. Lieber Markus**,

        vehicle.prototype = document.createElement("div");

        soweit ich Prototyping verstanden habe, muss nach dem Schlüsselwort "prototype" der Name einer Eigenschaft oder Methode stehen. Sowas wie die folgende Zeile hätte ich jetzt anstelle der oben zitierten erwartet:

        vehicle.prototype.element = document.createElement("div");

        Liebe Grüße,

        Felix Riesterer.

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

          Hallo Felix,

          vehicle.prototype = document.createElement("div");

          Soweit ich das verstanden habe, sage ich an dieser stelle sozusagen dass "this" ein Objekt vom Type element.div ist. Es handelt sich also um inheritance.

          Korrigiert mich, wenn ich falsch liege!

          Gruß, Markus**

          1. Der Prototyp ist ein Objekt, dessen Eigenschaften über das eigentliche Objekt gestülpt werden. Hier stülpst Du gerade die Eigenschaften eines divs über ein Function-Objekt, und das hat nun mal Eigenschaften, die der Browser nativ schützt.

            Gruß, LX

            --
            RFC 5984, Satz 7 (Security Considerations) (...) Terroristische Organisationen könnten die "Schlechte Nachrichten verbreiten sich schneller"-Schwachstelle aus RFC 1216 ausnutzen.
            1. Der Prototyp ist ein Objekt, dessen Eigenschaften über das eigentliche Objekt gestülpt werden.

              Der Prototyp ist das Objekt, an das delegiert wird, wenn die vehicle-Instanz eine angefragte Eigenschaft oder Methode nicht besitzt.

              Hier stülpst Du gerade die Eigenschaften eines divs über ein Function-Objekt, und das hat nun mal Eigenschaften, die der Browser nativ schützt.

              Welches Function-Objekt meinst du?

              Mathias

              1. Morgen, Mathias!

                Welches Function-Objekt meinst du?

                function vehicle(id) { ... }

                Dieses hier.

                Gruß, LX

                --
                RFC 5984, Satz 7 (Security Considerations) (...) Terroristische Organisationen könnten die "Schlechte Nachrichten verbreiten sich schneller"-Schwachstelle aus RFC 1216 ausnutzen.
                1. Super... danke Euch für die zahlreichen, konstruktiven Antworten.

                  Cheers, Markus**

        2. soweit ich Prototyping verstanden habe, muss nach dem Schlüsselwort "prototype" der Name einer Eigenschaft oder Methode stehen.

          Prinzipiell kann man der prototype-Eigenschaft jeden beliebigen Wert zuweisen. Anfangs enthält sie ein leeres(*) Objekt, dem man Eigenschaften und Methoden in der von dir beschriebenen Weise hinzufügen kann:

          func.prototype.neueEigenschaft = "foofoo";  
          func.prototype.neueMethode = function () {};
          

          Man kann die ganze Eigenschaft aber auch überschreiben. Eben mit dem Objekt, das als Prototyp für die Instanzen dient. Das kann ein eigenes sein oder irgendein bestehendes, an welches delegiert werden soll.

          func.prototype = {  
             neueEigenschaft : "foofoo",  
             neueMethode : function () {}  
          };
          

          oder eben

          func.prototype = window; // Ergibt i.d.R. wenig Sinn, ist aber möglich

          vgl. http://molily.de/js/organisation-instanzen.html

          (*) Es ist nicht komplett leer, sondern es gibt eine nicht durch for-in erreichbare Eigenschaft constructor, welche man löscht, wenn man den Wert von prototype mit einem eigenen Objekt überschreibt. Daher ist das Erzeugen von Membern mittels func.prototype.neueEigenschaft = ... schon sehr brauchbar.

          Mathias

          1. func.prototype = {

            neueEigenschaft : "foofoo",
               neueMethode : function () {}
            };

              
            interessant, aber bei Abänderung folgenden Codes  
            ~~~javascript
            Date.prototype.tag=function() {  
             return ["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"][this.getDay()];  
            }  
            Date.prototype.monat=function() {  
             return ["Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"][this.getMonth()];  
            }  
            
            

            in

            Date.prototype={  
             tag:function() {  
              return ["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"][this.getDay()];  
             },  
             monat:function() {  
              return ["Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"][this.getMonth()];  
             }  
            }  
            
            

            erhalte ich nur die Meldung (Opera11 + FF4) bla.tag() bzw. bla.monat() sei keine Funktion. Auch auf der verlinkten Seite finde ich dafür keine Erklärung. Gibt's eine?

            1. bei Abänderung folgenden Codes
              Date.prototype.tag=function() {};
              in

              Date.prototype={

              tag:function() {}
              };

                
              Das ist ja auch nicht das gleiche, sondern etwas ganz anderes. Das wollte ich auch ausdrücken.  
                
              Bei dem einen hängst du nur einen Member an ein bestehendes Objekt, beim zweiten überschreibst du das komplette Objekt mit einem neuen.  
                
              Beides geht - für die prototype-Eigenschaften EIGENER Funktionen.  
                
              Date.prototype ist hingegen ein eingebauter Prototyp. Du kannst ihn [nicht überschreiben](http://es5.github.com/#x15.9.4.1) ([[Writable]]: false), denn damit würdest du sämtliche bestehenden Methoden löschen. Auf diese Weise würde man alles nur kaputt machen. ECMAScript würde intern nicht mehr funktionieren, wenn du den Kern-Prototypen ihre Methoden wegnimmst.  
                
              Du kannst Date.prototype allerdings um neue Member erweitern.  
                
              Mathias
              
            2. Date.prototype={

              Nachtrag:

              Diese Zuweisung an eine nur lesbare Eigenschaft wird einfach ignoriert. Dieses Verhalten ist den Browsern so vorgeschrieben.

              Im Strict Mode hingegen wird diese Zuweisung eine Exception erzeugen, weil die Eigenschaft nur lesbar ist.

              Mathias

      2. function vehicle(id) {

        Konstruktoren sollte man groß schreiben, um sie von Instanzen unterscheiden zu können. Also »Vehicle«. Dann ist immer klar, dass sie zusammen mit »new« verwendet werden.

        vehicle.prototype = document.createElement("div");

        Prinzipiell kannst du so arbeiten, aber von der Logik her halte ich das nicht für passend. *Ist* eine vehicle-Instanz ein spezielles div? Nein, es *hat* offenbar ein div, mit dem es z.B. dargestellt wird, oder?

        Übrigens nutzen hier alle vehicle-Instanzen dasselbe div, das ist dir klar, oder? Es gibt hier nur ein einziges div, an das delegiert wird, denn alle Instanzen haben ein und denselben Prototyp.

        Daher würde ich das div einfach im Konstruktor erzeugen, etwa
        this.element = document.createElement('div');

        Zu deinem Firefox-Problem: Im Firefox funktioniert es einfach nicht, ein konkretes Elementobjekt um eine Methode zu erweitern, das Elementobjekt als Prototyp zu verwenden und schließlich die Methode des Elementobjekts per prototypische Delegation auf der Instanz aufzurufen.

        Ehrlich gesagt weiß ich auch nicht, wieso man das tun sollte. Es mag manchmal sinnvoll sein, an ein Elementknoten prototypisch zu delegieren. Dann würde ich die Methoden dieses Wrappers aber nicht dem gewrappten Elementobjekt verpassen, sondern dem Wrapper. Wenn es viele Wrapper gibt, dann würde ich als Prototyp ein eigenes Objekt verwenden, welches wiederum an das Elementobjekt delegiert.

        Ich kann mir aber nicht vorstellen, dass du mit solch langen Prototyp-Ketten arbeiten willst. Üblicher ist wie gesagt, dass ein Objekt ein Elementobjekt *hat* (this.element o.ä.). Was willst du erreichen?

        Mathias