Ergebnis 1 bis 13 von 13
  1. #1
    JonasP ist offline Grünschnabel
    registriert
    27-05-2012
    Beiträge
    4

    Question Zugriff auf Objektklasse nach EventHandler (this)

    Hallo zusammen!
    Angenommen man erstellt ein Javascript-Objekt ("test"), das einen Button (this.button) und ein paar Daten (this.content) kapselt. Wenn man einem Button per addEventListener eine klasseneigene Funktion (this.clix) zuweist, ist in dieser Funktion this gleich dem EventObjekt und verweist nicht auf die Instanz der Klasse (test). Will man auf die Instanz der Klasse zugreifen ist es daher üblich eine lokale Variable zu erstellen (var self = this;), die dann in der Eventhandler-Funktion die Referenz auf das Klassenobjekt zurück liefert. - Das funktioniert soweit gut.
    Erstellt man jetzt eine komplexere Klasse, die man von einer anderen Klasse (testproto) per prototype ableitet, funktioniert das nicht mehr:
    Code:
    <html>
    <head>
    <title>Closure test</title>
    <script type="text/javascript">
    	function testproto ()
    	 {
    		var self = this;
    		this.init = function (btn, alttext)
    		 {
    			this.alttext = alttext;
    			this.button = btn;
    		 }
    	 }	 	
    
    	function test(btn, text, alttext)
    	 {
    		var self = this;
    		this.init = function (btn, text, alttext)
    		 {
    			this.__proto__.init(btn, alttext);
    			this.content = text;
    			
    			btn.addEventListener("click", this.clix);			
    		 }
    		this.clix = function (e)
    		 {
    			self.button.innerHTML = self.content;
    		 }
    		this.init (btn, text);
    	 }
    	
    	test.prototype = new testproto();
    	 
    </script>
    </head>
    <body>
    	<button type="button" id="northpole">Hello North Pole</button><br>
    	<button type="button" id="sahara">Hello Sahara</button><br>
    	<script type="text/javascript">
    		var btn1 = document.getElementById('northpole');
    		var test1 = new test(btn1, "Cold 1");
    		var btn2 = document.getElementById('sahara');
    		var test2 = new test(btn2, "Warm 2");
    	</script>
    </body>
    </html>
    Wieso ändert sich nur der zweite Button, obwohl ich doch auf den ersten drücke? - Weiß jemand eine Lösung?

    Danke

  2. #2
    Avatar von kkapsner
    kkapsner ist offline Super Moderator
    registriert
    28-03-2008
    Beiträge
    17.678

    AW: Zugriff auf Objektklasse nach EventHandler (this)

    Diese Art der "Verebung" ist aber nicht besonders gutartig (z.B. ist this.constructor nicht mehr die richtige Funktion) und kann zu massiven Problemen führen, wenn im Constructor der Elternklasse wirklich effetkiv etwas gemacht wird.

    Zu deinem Problem: überleg' dir mal, welchen Wert this im Aufruf von this.__proto__.init(...) hat.

    PS: nicht alle Browser unterstützen __proto__. Eine sichere Variante (wenn man die Vererbung sauber macht) wäre this.constructor.prototype.

  3. #3
    JonasP ist offline Grünschnabel
    registriert
    27-05-2012
    Beiträge
    4

    AW: Zugriff auf Objektklasse nach EventHandler (this)

    Das mit __proto__ ist ein guter Hinweis, danke.
    Hast du für die Vererbung einen Tipp, wie es sauberer geht? - Vielleicht löst das ja mein Problem.

  4. #4
    JonasP ist offline Grünschnabel
    registriert
    27-05-2012
    Beiträge
    4

    AW: Zugriff auf Objektklasse nach EventHandler (this) - Fortschritt

    Okay, ich habe nochmal rumgebastelt. Mit
    Code:
    var clixer = this.clix.bind(this);	// innerhalb von clix ist this immer diese Funktion
    			btn.addEventListener("click", clixer);
    ist innerhalb von clix(e) this gleich dem Objekt, das aufgerufen wurde.
    Das Problem ist jedoch ein anderes: testproto wird nicht bei jedem neuen new test(...) mit erstellt. - Warum erstellt ein abgeleitetes Objekt seinen "Vater" nicht gleich mit?
    Und wie kann man das Problem lösen?

  5. #5
    Avatar von kkapsner
    kkapsner ist offline Super Moderator
    registriert
    28-03-2008
    Beiträge
    17.678

    AW: Zugriff auf Objektklasse nach EventHandler (this)

    Ich hab' mir folgende Vererbung zusammengebaut: http://kkjs.kkapsner.de/modules/kkjs.oo.js

    Dein Problem liegt nicht in der Funktion clix, sondern im Aufruf von this.__proto__.init.

    Warum sollte der testproto bei jedem new mit erstellt werden? Das ist ja noch nicht einmal in OO-Sprachen der Fall... und JS ist nicht OO, sondern prototype-orientiert. Damit kann man viele tolle Sachen machen, aber wirklichliche Klassen werden damit etwas schwierig.

  6. #6
    ein schlauer ist offline Lounge-Member
    registriert
    18-08-2004
    Beiträge
    14.671

    AW: Zugriff auf Objektklasse nach EventHandler (this) - Fortschritt

    Zitat Zitat von JonasP Beitrag anzeigen
    Warum erstellt ein abgeleitetes Objekt seinen "Vater" nicht gleich mit?
    Und wie kann man das Problem lösen?
    Weil es nicht aufgerufen wird. Der einfachste Weg mit JS zu vererben wäre in deinem Fall so:
    Code:
    <!DOCTYPE html>
    <html>
    <head>
    <title></title>
    <script type="text/javascript">
    // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/create
    Object.create = Object.create || function(proto) {
        function F() {}
        F.prototype = proto;
        return new F();
    };
    
    function Testproto(btn, alttext){
    	var self = this;
    	this.alttext = alttext;
    	this.button = btn;
    }	 	
    
    function Test(btn, text, alttext){
    	Testproto.call(this, btn, alttext);
    	var self = this;
    	
    	this.content = text;
    	
    	
    	this.clix = function (e){
    		self.button.innerHTML = self.content;
    	};
    	btn.addEventListener("click", this.clix, false);			
    }
    	
    Test.prototype = Object.create(Testproto.prototype);
    </script>
    
    </head>
    <body>
    	
    	<button type="button" id="northpole">Hello North Pole</button><br>
    	<button type="button" id="sahara">Hello Sahara</button><br>
    	<script type="text/javascript">
    		var btn1 = document.getElementById('northpole');
    		var test1 = new Test(btn1, "Cold 1");
    		var btn2 = document.getElementById('sahara');
    		var test2 = new Test(btn2, "Warm 2");
    	</script>
    	
    </body>
    </html>
    Statt Testproto aufzurufen, könntest du auch Test.prototyope.constructor benutzen.

  7. #7
    ein schlauer ist offline Lounge-Member
    registriert
    18-08-2004
    Beiträge
    14.671

    AW: Zugriff auf Objektklasse nach EventHandler (this)

    Zitat Zitat von kkapsner Beitrag anzeigen
    Das ist ja noch nicht einmal in OO-Sprachen der Fall... und JS ist nicht OO, sondern prototype-orientiert. Damit kann man viele tolle Sachen machen, aber wirklichliche Klassen werden damit etwas schwierig.
    Naja, OO heißt ja Objektorientiert und für mich ist Javascript durchaus Objektorientiert. prototype basiert ist die Umsetzung der Vererbung.

    Und was "wirkliche Klassen" sind dürfte das eine reine Definitionsfrage sein. Java Anhänger proklamieren hier zwar für sich eine Deutungshoheit, aber auch bei fehlenden Schlüsselwörtern lassen sich die meisten Muster einer objektorientierten Programmierung umsetzen. Wobei ich aber von dem Versuch dies 1:1 umzusetzen abgekommen bin. Die Performanceverluste halte ich für zu gravierend. Daher mache ich sowas nur noch auf möglichst direktem Weg.

  8. #8
    JonasP ist offline Grünschnabel
    registriert
    27-05-2012
    Beiträge
    4

    Lightbulb AW: Zugriff auf Objektklasse nach EventHandler (this)

    Danke Korbinian, danke ein schlauer.
    Mein test.prototype = new testproto(); hat ja nur einmal (beim ersten Durchlaufen des Scriptes) ein neues testproto-Objekt erzeugt. Alle anderen test-Objekte haben darauf verwiesen. Mit dem Erfolg, das this.button, immer auf das Element verwiesen hat, das zuletzt durch Aufruf von test(...) gesetzt wurde.

    Nach einem Umbau (s. u.) war this.button plötzlich gar nicht mehr definiert, weil, da hast du, Korbinian Recht, der __proto__.init-Aufruf in die Irre führt. Init habe ich daher rausgeschmissen und setze die Werte im Konstruktor - das funktioniert.

    Lösung: Letztendlich habe ich sowohl extend (Korbinian) als auch Object.create (ein schlauer) verwendet. Im Verständnis hat mir letzendlich quildreens Tutorial weitergeholfen. Entscheidend war auf die Funktion .bind(..) die etliche Probleme von EventHandlern etc. löst.
    Code:
    <html>
    <head>
    <title>Closure test</title>
    <script type="text/javascript">
    
    function extend(target, source)
    	{
    		Object.getOwnPropertyNames(source).forEach(
    				function(key) 
    				 {
    					Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)) 
    				 });
    		return target;
    	}
    	
    function testproto(btn, alttext)				// Aufruf von testproto entsprich einer Init-Funktion (constructor)
    	{
    		this.alttext = alttext;
    		this.button = btn;
    	}
    	
    testproto.prototype = Object.create(null);		// testproto.prototype von leerem Objekt ableiten
    
    testproto.fn = {								// Funktionen und Parameter für testproto.fn definieren
    	constructor: testproto
    	}
    
    extend(testproto.prototype, testproto.fn);		// die in testproto.fn definierten Funktionen auf testproto.prototype übertragen
    
    function test (btn, text, alttext)
    	{
    		 Object.getPrototypeOf(test.prototype).constructor.call(this, btn, alttext);
    		 this.content = text;
    		console.log(self.content);
    		var clixer = this.clix.bind(this);	// innerhalb von clix ist this immer diese Funktion
    		btn.addEventListener("click", clixer);
    	}	 
    
    	 
    test.prototype = Object.create(testproto.prototype);	// test.prototype von testproto.prototype ableiten
    
    test.fn = {												// Funktionen und Parameter für test.fn definieren
    			constructor: test,
    			clix: function (e)
    			 {
    				this.button.innerHTML = this.content;
    			 }
    		  }
    
    	extend(test.prototype, test.fn);					// die in test.fn definierten Funktionen auf test.prototype übertragen
    </script>
    </head>
    <body>
    	<button type="button" id="northpole">Hello North Pole</button><br>
    	<button type="button" id="sahara">Hello Sahara</button><br>
    	<script type="text/javascript">
    		var btn1 = document.getElementById('northpole');
    		test1 = new test(btn1, "Cold 1", "Diemar 1");
    		var btn2 = document.getElementById('sahara');
    		test2 = new test(btn2, "Warm 2", "Eduard 2");
    	</script>
    </body>
    </html>
    Also Danke, für die Hilfe!
    Geändert von JonasP (03-06-2012 um 22:08 Uhr) Grund: quildreens URL war falsch

  9. #9
    Avatar von kkapsner
    kkapsner ist offline Super Moderator
    registriert
    28-03-2008
    Beiträge
    17.678

    AW: Zugriff auf Objektklasse nach EventHandler (this)

    @ein schlauer: ja - JS basiert sehr stark auf Objekten (alles ist ein Objekt), aber es fehlen doch einige wichtige Punkte (in meinen Augen) wie Aufruf von Funktionen weiter oben im Vererbungsbaum mit der Sicherheit der richtigen Ebene (Bsp.: drei Klassen (A, B und C), die in einer Kette voneinander erben (A erbt von B und B von C) und alle eine eigene Implementation einer Funktion haben (sgen wir mal test()). In jeder Funktion wollen wir aber die "Elternfunktion" auch aufrufen. Bei einer günstigen Konstellation können wir das mit this.prototype.test.call(this) machen, aber wenn wir jetzt INSTANZ_VON_A.test() Aufrufen kommen wir in eine Endlosschleife) oder Datenkapselung, so dass ich nicht von OO reden würde (du darfst das gerne, wenn du willst - wir leben in einem freien Land). Dass man das mit geschicktem Hantieren mit Closures/dynamischem Eigenschaftswechel/etc. imitieren kann ändert daran eigentlich nichts. Du kannst auch mit reinem C dir eine OO-Umgebung aufbauen...

    @JonasP: Ich finde deinen Ansatz sehr kompliziert und du verlässt dich da auf viele Methoden aus ECMA-262 5th Edition, die noch nicht in allen Browsern implementiert sind (z.B: Object.create).
    PS: Dein inkonsistentes Codestyling erleichtert das Nachvollziehen auch nicht wirklich...

  10. #10
    ein schlauer ist offline Lounge-Member
    registriert
    18-08-2004
    Beiträge
    14.671

    AW: Zugriff auf Objektklasse nach EventHandler (this)

    Zitat Zitat von kkapsner Beitrag anzeigen
    @ein schlauer: ja - JS basiert sehr stark auf Objekten (alles ist ein Objekt), aber es fehlen doch einige wichtige Punkte (in meinen Augen) wie Aufruf von Funktionen weiter oben im Vererbungsbaum mit der Sicherheit der richtigen Ebene (Bsp.: drei Klassen (A, B und C), die in einer Kette voneinander erben (A erbt von B und B von C) und alle eine eigene Implementation einer Funktion haben (sgen wir mal test()). In jeder Funktion wollen wir aber die "Elternfunktion" auch aufrufen. Bei einer günstigen Konstellation können wir das mit this.prototype.test.call(this) machen, aber wenn wir jetzt INSTANZ_VON_A.test() Aufrufen kommen wir in eine Endlosschleife) oder Datenkapselung, so dass ich nicht von OO reden würde (du darfst das gerne, wenn du willst - wir leben in einem freien Land). Dass man das mit geschicktem Hantieren mit Closures/dynamischem Eigenschaftswechel/etc. imitieren kann ändert daran eigentlich nichts. Du kannst auch mit reinem C dir eine OO-Umgebung aufbauen...
    Klar, kann man das.

    OOP heißt ja nicht das das eine Sprache bestimmte Schlüsselwörter hat, sondern es heißt dass du Objektorientiert programmierst. Jede OO Sprache hat für die einzelnen Konzepte andere Umsetzungen und manche Sachen die mit JS gehen, können andere Sprachen gar nicht. Es ist halt einfach die Frage, ob man es gerne flexibel mag oder ob man sich gerne an strengere Regeln halten möchte. Ausserdem ist es natürlich ein Unterschied, ob du eine Skript- oder eine kompilierte Sprache hast. In Skriptsprachen kannst du während der Laufzeit viel mehr ändern, sogar neue Klassen kreieren.

    Kapselung läßt sich perfekt mir closures umsetzen. Ich halte das nicht für "hantieren", sondern ein Sprachkonzept. Nichtsdestotrotz gibt es mittlerweile auch andere Möglichkeiten.

    Das Aufrufen der Superklasse ist mit JS einfach über die Eigenschaft ElternKlasse.prototype (nicht über this!) möglich. Wenn du die Funktion im Konstruktor überschreibst, musst du dir die Referenz dort selber sichern, ein sehr flexibles OO Konzept.

    Ich weiß nicht, warum du es an ein zwei Punkten festmachen willst ob eine Sprache Objektorientiert ist oder nicht. Zumal, wie du schon sagst, JS überwiegend auf Objekten basiert.

    Zitat Zitat von kkapsner Beitrag anzeigen
    @JonasP: Ich finde deinen Ansatz sehr kompliziert und du verlässt dich da auf viele Methoden aus ECMA-262 5th Edition, die noch nicht in allen Browsern implementiert sind (z.B: Object.create).
    Dafür hatte ich eine Lösung schon gezeigt. Aber ansonsten finde ich meinen Ansatz auch einfacher.

  11. #11
    Avatar von kkapsner
    kkapsner ist offline Super Moderator
    registriert
    28-03-2008
    Beiträge
    17.678

    AW: Zugriff auf Objektklasse nach EventHandler (this)

    Die beiden Punkte waren nur Beispiele (und die Lösung des Kapselungsproblems mit Closures, den "privilegierten" Funktionen, mag' ich persönlich nicht, da es nicht sowas wie einen protected Status gibt und es dann Funktionen gibt, die nicht im prototype verankert sind, was mir konzeptionell nicht gefällt).

    Aber egal - ich würde es nicht OO nennen... und so wie ich dich verstehe (korrigier' mich, wenn ich dich falsch verstanden habe), ist für dich jede Sprache OO - man muss sie nur entsprechend benutzen.

  12. #12
    ein schlauer ist offline Lounge-Member
    registriert
    18-08-2004
    Beiträge
    14.671

    AW: Zugriff auf Objektklasse nach EventHandler (this)

    Nein, OOP ist ein Konzept, dass nicht an eine Programmiersprache gebunden ist. Und jede OO Sprache hat für die einzelnen Muster unterschiedliche herangehensweise. Deshalb bin ich auch davon etwas abgekommen zu versuchen mit JS jedes Paradigma umzusetzen.

    Das Grundkonzept ist aber das Vorhandensein von Objekten oder Strukturen, mit denen Attribute und Methoden verbunden sind. Vererbung und Kapselung würde ich ebenfalls als Grundlagen bezeichnen, wobei die Kapselung in JS ja durchaus möglich ist, auch wenn du die Methode nicht magst, aber nur weil nicht alles so möglich ist, wie in Java oder Smalltalk ist eine Sprache nicht nicht OOP. Prototypen sind ein Zeichen für eine OO Sprache.

  13. #13
    Avatar von kkapsner
    kkapsner ist offline Super Moderator
    registriert
    28-03-2008
    Beiträge
    17.678

    AW: Zugriff auf Objektklasse nach EventHandler (this)

    OK - jetzt verstehe ich dich. Mit JS kann man natürlich OOP machen.

    Für mich ist z.B. Java eine OO-Sprache, weil hier das Sprachkonzept komplett für die OOP ausgelegt wurde. JS ist (für mich) keine OO-Sprache, da das Sprachkonzept einige OO-Bereiche schlecht bis gar nicht abbildet. Dass man das (meistend) nachbilden kann ist eine der Stärken von JS (ich mag JS auch lieber als Java), macht es aber (in meinen Augen) nicht zu einer OO-Sprache. Es hat Ansätze (prototype) - aber ein wedelnder Schwanz macht noch keinen Hund.

    Ich trenne also OOP und OO ohne P...

Ähnliche Themen

  1. Objektklasse
    Von klaus92 im Forum JavaScript
    Antworten: 1
    Letzter Beitrag: 27-12-2009, 19:08
  2. JS DOM und Eventhandler
    Von AlphaGen im Forum JavaScript
    Antworten: 4
    Letzter Beitrag: 27-10-2008, 17:39
  3. Eventhandler hinzufügen (IE)
    Von xelax90 im Forum JavaScript
    Antworten: 3
    Letzter Beitrag: 29-12-2007, 17:06
  4. if-Schleife für Eventhandler
    Von flobb im Forum JavaScript
    Antworten: 2
    Letzter Beitrag: 30-10-2007, 15:05
  5. eventhandler auf iframe
    Von sanchez im Forum JavaScript
    Antworten: 1
    Letzter Beitrag: 25-09-2003, 21:03

Stichworte

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •