Siri: Neues JS-Objekt innerhalb eines Scopes?

Hallo,

an der Stelle mit den drei *** dachte ich, ich hätte ein Objekt erzeugt.
Wenn man die Seite aufruft und zuerst auf die obere Liste klickt und dann auf die untere, dann gibt der alert "true" zurück, d.h. this.moveInProgress ist Objektübergreifend bzw. mein vermeintlichen Objekte sind keine. Was mache ich falsch?

Viele Grüße
Siri

PS: function myContentLoaded nur der Vollständigkeit halber, habe ich über molily.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">  
<html xmlns="http://www.w3.org/1999/xhtml">  
	<head>  
		<meta charset="utf-8"/>  
		<title></title>		  
	</head>  
	<body>	  
		<!-- ====================== -->  
		<ul id="wrapper1" class="changeposul">  
			<li id="fd1">a1</li>  
			<li id="fd2">a2</li>  
			<li id="fd7">a7</li>  
		</ul>  
		<!-- ====================== -->  
		<ul id="wrapper2" class="changeposul">  
			<li id="fda">a1</li>  
			<li id="fdb">a2</li>  
		</ul>  
		<!-- ====================== -->  
		<script>
var MyFW = (function () {  
  
	function init() {	  
  
		var changePosULsArray = document.getElementsByClassName('changeposul');		  
		for (var y= 0; y < changePosULsArray.length; y++) {				  
  
			// *** Neues Objekt oder nicht???  
			var liChangePosHandlerLoop = new LiChangePosHandler();  
			liChangePosHandlerLoop.init();  
			  
			if (document.addEventListener) {				  
				changePosULsArray[y].addEventListener("click", liChangePosHandlerLoop.moveUp,  false);		  
			} else {					  
				changePosULsArray[y] = liChangePosHandlerLoop.moveUp;		  
			}					  
			  
		}	  
  
	}  
	  
	return {		  
		afterLoad: function() {		  
			init();	  
		}	  
	}  
	  
	function LiChangePosHandler() {  
	  
		this.moveInProgress;  
		  
		this.init = function() {  
			moveInProgress = false;  
		}  
		  
		this.moveUp = function(eventObject) {		  
			  
			alert(moveInProgress);  
			  
			if (moveInProgress == false) {  
				moveInProgress = true;			  
				// Do anything  
			}		  
		  
		};		  
		  
	}  
	  
})();	  
		  
myContentLoaded (window, MyFW.afterLoad );
		</script>  
	</body>  
</html>  

Der Vollständigkeit halber:

function myContentLoaded(win, fn) {  
  
	var done = false, top = true,  
  
	doc = win.document, root = doc.documentElement,  
  
	add = doc.addEventListener ? 'addEventListener' : 'attachEvent',  
	rem = doc.addEventListener ? 'removeEventListener' : 'detachEvent',  
	pre = doc.addEventListener ? '' : 'on',  
  
	init = function(e) {  
		if (e.type == 'readystatechange' && doc.readyState != 'complete') return;  
		(e.type == 'load' ? win : doc)[rem](pre + e.type, init, false);  
		if (!done && (done = true)) fn.call(win, e.type || e);  
	},  
  
	poll = function() {  
		try { root.doScroll('left'); } catch(e) { setTimeout(poll, 50); return; }  
		init('poll');  
	};  
  
	if (doc.readyState == 'complete') {  
		fn.call(win, 'lazy');  
	} else {  
		if (doc.createEventObject && root.doScroll) {  
			try { top = !win.frameElement; } catch(e) { }  
			if (top) poll();  
		}  
		doc[add](pre + 'DOMContentLoaded', init, false);  
		doc[add](pre + 'readystatechange', init, false);  
		win[add](pre + 'load', init, false);  
	}  
	  
}
  1. Hallo Siri,

    function LiChangePosHandler() {

      this.moveInProgress;  
    

    was macht diese Zeile?

      this.init = function() {  
      	moveInProgress = false;  
    

    hier legst du eine globale Variable an.

    Gruß, Jürgen

    1. Hallo,

      function LiChangePosHandler() {  
      
        this.moveInProgress;  
      

      was macht diese Zeile?

      Ich dachte ich instanziere damit die Variable...

        this.init = function() {  
        	moveInProgress = false;  
      

      hier legst du eine globale Variable an.

      Aber warum ist das keine globale Variable der Instanz, die dann den Methoden zur Verfügung steht?

      Viele Grüße
      Siri

      1. Hallo Siri,

          	moveInProgress = false;  
        

        hier legst du eine globale Variable an.

        Aber warum ist das keine globale Variable der Instanz, die dann den Methoden zur Verfügung steht?

        x = 42; legt eine globale Variable an,
        var x = 42; legt eine lokale Variable im aktuellen Objekt an,
        this.x = 42; erweitert das aktuelle Objekt um die Eigenschaft x.

        Gruß, Jürgen

        1. Hallo,

          x = 42; legt eine globale Variable an,
          var x = 42; legt eine lokale Variable im aktuellen Objekt an,
          this.x = 42; erweitert das aktuelle Objekt um die Eigenschaft x.

          Dann so?

          this.moveInProgress;  
            
          this.init = function() {  
           this.moveInProgress = false;  
          }  
            
          this.moveUp = function(eventObject) {  
            
           alert(this.moveInProgress);  
            
           if (this.moveInProgress == false) {  
            this.moveInProgress = true;  
            // Do anything  
            }  
            
          };   
          

          Viele Grüße
          Siri

          1. Hallo Siri,

            Dann so?

            bis auf das überflüssige

            this.moveInProgress;

            würde ich ja sagen. Funktioniert es denn wie gewünscht?

            Gruß, Jürgen

            1. Hallo,

              würde ich ja sagen. Funktioniert es denn wie gewünscht?

              Leider nein:

              function LiChangePosHandler() {  
                
              	this.init = function(wert) {  
              		this.moveInProgress = false;  
              		this.test = wert;  
              	}  
              	  
              	this.moveUp = function(eventObject) {		  
              		  
              		alert(this.moveInProgress+"|"+this.test);  
              		// Ergebnis: undefined|undefined  
                
              		if (this.moveInProgress == false) {  
              			this.moveInProgress = true;					  
              		}		  
              		  
              		testFunc();  
              		  
              	};		  
              	  
              	testFunc = function() {  
              		alert(this.moveInProgress+"|"+this.test);  
                              // Ergebnis: undefined|undefined  
              	}  
              	  
              }
              

              Viele Grüße
              Siri

              1. Hallo Siri,

                ich vermute, du rufst moveup in einem Eventhandler auf, denn dann zeigt this auf das das Event auslösende Element. In solchen Fällen speichere ich this in einer extra variable:

                var dieses = this; // am Anfang des Objekts

                ...

                alert(dieses.moveInProgress+"|"+dieses.test); // im Eventhandler

                Gruß, Jürgen

                1. Hallo,

                  ich vermute, du rufst moveup in einem Eventhandler auf, denn dann zeigt this auf das das Event auslösende Element. In solchen Fällen speichere ich this in einer extra variable:

                  var dieses = this; // am Anfang des Objekts

                  ...

                  alert(dieses.moveInProgress+"|"+dieses.test); // im Eventhandler

                  Das ist auch eine Variante, wobei mir die andere vom "Stil" her näher liegt, dann muss ich auch nicht immer auf "dieses." referenzieren.

                  Viele Grüße
                  Siri

                  1. Hallo Siri,

                    ... die andere ...

                    irgendwie verstehe ich jetzt weder dein Problem, noch wie du es gelöst hast. Wäre schön, wenn du deine Lösung hier posten könntest.

                    Gruß, Jürgen

                    1. Hallo,

                      irgendwie verstehe ich jetzt weder dein Problem, noch wie du es gelöst hast. Wäre schön, wenn du deine Lösung hier posten könntest.

                      ???

                      Na so, wie es im Link gepostet wurde:

                      var xy

                      statt

                      this.xy

                      und

                      function abc(){

                      }

                      statt

                      abc = function(){

                      }

                      Viele Grüße
                      Siri

                      1. irgendwie verstehe ich jetzt weder dein Problem, noch wie du es gelöst hast. Wäre schön, wenn du deine Lösung hier posten könntest.

                        Geht mir immer noch so.

                        Na so, wie es im Link gepostet wurde:

                        In welchem Link? Der unter "Gelöst"? Das war ja überhaupt nicht dein Problem. Dein Problem ist ja, daß das Objekt, welches den Eventhandler aufruft, nicht das ist, welches du als this erwartest. Egal es sich um eine Funktion am Prototypen oder am Objekt selbst handelt.
                        Wenn dir die explizite Speicherung der des Objektes in "dieses" nicht gefällt, mach es über eine weitere Closure:

                        function getHandler()
                        {
                          var liChangePosHandlerLoop = new LiChangePosHandler();
                          liChangePosHandlerLoop.init();
                          return liChangePosHandlerLoop.moveUp;
                        }
                        if (document.addEventListener) {
                                                        changePosULsArray[y].addEventListener("click", getHandler(),  false);
                                                } else {

                        // was macht das hier eigentlich???
                                                        changePosULsArray[y] = liChangePosHandlerLoop.moveUp;
                                                }

                        1. Hallo,

                          In welchem Link? Der unter "Gelöst"? Das war ja überhaupt nicht dein Problem. Dein Problem ist ja, daß das Objekt, welches den Eventhandler aufruft, nicht das ist, welches du als this erwartest. Egal es sich um eine Funktion am Prototypen oder am Objekt selbst handelt.

                          Genau das ist das Problem und das Problem ist damit gelöst, dass ich ein privates Objekt erzeuge (etwas nach unten scrollen!).

                          // was macht das hier eigentlich???
                                                          changePosULsArray[y] = liChangePosHandlerLoop.moveUp;
                                                  }

                          changePosULsArray[y].onclick = liChangePosHandlerLoop.moveUp;

                          Viele Grüße
                          Siri

                          1. In welchem Link? Der unter "Gelöst"? Das war ja überhaupt nicht dein Problem. Dein Problem ist ja, daß das Objekt, welches den Eventhandler aufruft, nicht das ist, welches du als this erwartest. Egal es sich um eine Funktion am Prototypen oder am Objekt selbst handelt.

                            Genau das ist das Problem und das Problem ist damit gelöst, dass ich ein privates Objekt erzeuge (etwas nach unten scrollen!).

                            Meiner Meinung nach nicht. Dadurch, dass du auf eine lokale Variable (deine "private" Variable) ausweichst umgehst du das Problem.
                            Das Problem, dass du eine Objekt-Funktion(s-Eigenschaft) mit dem falschen Objekt aufrufst besteht weiterhin und ist (würde ich mal behaupten) in diesem Fall auch nicht gewollt.
                            Wenn du jetzt oder später eine weitere Funktion dieses Objektes innerhalb des Eventhandlers aufrufen willst, oder auf andere Eigenschaften dieses Objektes zurückgreifen musst, hast du das Problem wieder. Diese müsstest du sonst alle lokal machen, das wird nicht in jedem Fall funktionieren.
                            Das soll nicht heissen, das moveInProgress nicht lokal liegen sollte. Das finde ich unabhängig davon richtig.

                            1. Hallo,

                              deiner Argumentation kann ich jetzt rein fachlich nicht mehr ganz folgen...

                              Was meine gesamte Funktion insgesamt macht ist, in einer Liste die Position von zwei Listenpunkten auszutauschen. Das soll natürlich auch bei mehreren Listen unabhängig funktionieren.
                              Im ursprünglichen Script sind die jeweiligen Positionen durcheinander gekommen, jetzt arbeiten sie unabhängig voneinander. D.h. für mich, das jeder EventHandler sein eigenes "Objekt" hat, indem die jeweiliegen Zustände der Liste gespeichert und verarbeitet werden. Der Eventhandler findet also das zu ihm gehörende "Objekt". Einen Fehlerfall konnte ich nicht produzieren.

                              Viele Grüße
                              Siri

                              1. Du hast ein Objekt welches unter anderem einen Eventhandler als Property hat. Dass dieser Handler an einem Objekt liegt, ist also gewollt. Dann sollte man ihn auch mit diesem Objekt als Context aufrufen.
                                Du hattest jetzt

                                <html>
                                  <head>
                                    <title>test</title>
                                  </head>
                                  <body>
                                    <a>===1===</a>
                                    <a>===2===</a>
                                    <script type="text/javascript">
                                      function XXX()
                                      {
                                        this.test = 0;
                                        this.handler = function()
                                        {
                                          alert(this.test++);
                                        }
                                      }
                                      function getHandler()
                                      {
                                        var xxx = new XXX();
                                        return xxx.handler;
                                      }
                                      var elems = document.getElementsByTagName("a");
                                      for (var i = 0; i < elems.length; i++)
                                      {
                                        elems.item(i).onclick = getHandler();
                                      }
                                    </script>
                                  </body>
                                </html>

                                und dort das Problem, dass der Handler mit dem falschen Objekt aufgerufen wurde. Damit ist "this.test" nicht vorhanden.
                                Umgangen hast du es indem du aus der Eigenschaft this.test eine lokale Variable var test gemacht hast. Der Handler wird aber immer noch mit dem falschen Context aufgerufen.
                                Willst du jetzt auf eine weitere Objekteigenschaft im Handler zugreifen, wird es immer noch nicht funktionieren

                                <html>
                                  <head>
                                    <title>test</title>
                                  </head>
                                  <body>
                                    <a>===1===</a>
                                    <a>===2===</a>
                                    <script type="text/javascript">
                                      function XXX()
                                      {
                                        var test = 0;
                                        this.handler = function()
                                        {
                                          alert(this.setFlag())
                                        }
                                        this.setFlag = function()
                                        {
                                          return test++;
                                        }
                                      }
                                      function getHandler()
                                      {
                                        var xxx = new XXX();
                                        return xxx.handler;
                                      }
                                      var elems = document.getElementsByTagName("a");
                                      for (var i = 0; i < elems.length; i++)
                                      {
                                        elems.item(i).onclick = getHandler();
                                      }
                                    </script>
                                  </body>
                                </html>

                                Darum solltest du das eigentliche Problem beheben und den Handler mit dem entsprechenden Context aufrufen.

                                <html>
                                  <head>
                                    <title>test</title>
                                  </head>
                                  <body>
                                    <a>===1===</a>
                                    <a>===2===</a>
                                    <script type="text/javascript">
                                      function XXX()
                                      {
                                        var test = 0;
                                        this.handler = function()
                                        {
                                          alert(this.setFlag())
                                        }
                                        this.setFlag = function()
                                        {
                                          return test++;
                                        }
                                      }
                                      function getHandler()
                                      {
                                        var xxx = new XXX();
                                        return function()
                                        {
                                          xxx.handler();
                                        }
                                      }
                                      var elems = document.getElementsByTagName("a");
                                      for (var i = 0; i < elems.length; i++)
                                      {
                                        elems.item(i).onclick = getHandler();
                                      }
                                    </script>
                                  </body>
                                </html>

                                1. Du hast ein Objekt welches unter anderem einen Eventhandler als Property hat. Dass dieser Handler an einem Objekt liegt, ist also gewollt. Dann sollte man ihn auch mit diesem Objekt als Context aufrufen.

                                  Ich hab doch eher Elemente, die einen (eigenen) EventHandler mit dem zugehörigen Objekt haben:

                                  var changePosULsArray = document.getElementsByClassName('changeposul');
                                  for (var y= 0; y < changePosULsArray.length; y++) {

                                  var liChangePosHandlerLoop = new LiChangePosHandler();
                                   liChangePosHandlerLoop.init();
                                   changePosULsArray[y].addEventListener("click", liChangePosHandlerLoop.moveUp,  false);

                                  }

                                  Wenn das Objekt jetzt Privat ist, dann kommen sie sich auch nicht ins Gehege, da das Objekt über den Eventhandler am Element hängt.

                                  1. var changePosULsArray = document.getElementsByClassName('changeposul');
                                    for (var y= 0; y < changePosULsArray.length; y++) {

                                    var liChangePosHandlerLoop = new LiChangePosHandler();
                                    liChangePosHandlerLoop.init();
                                    changePosULsArray[y].addEventListener("click", liChangePosHandlerLoop.moveUp,  false);

                                    }

                                    Wenn das Objekt jetzt Privat ist, dann kommen sie sich auch nicht ins Gehege, ...

                                    Das Objekt oben ist lokal. Prinzipiell gibt es erst mal kein "private" in js. Im Zusammenhang mit Objekten und der Sichtbarkeit von lokalen Variablen/Eigenschaften kann man von private/public sprechen. Hier gibt es aber nur eine Schleife mit lokalen Objekten.
                                    Das ist ja aber auch nicht die Variable von der wir(?) reden.  Ich meine "moveInProgress". Die hast du doch lokal gelegt, damit es erst mal geht?

                                    ... da das Objekt über den Eventhandler am Element hängt.

                                    und genau das macht es nicht, das sage ich ja die ganze Zeit!

                                    1. ... da das Objekt über den Eventhandler am Element hängt.
                                      und genau das macht es nicht, das sage ich ja die ganze Zeit!

                                      Aber wieso sollte es dann funktionieren? Ich kann bei beliebig vielen Listen parallel die Position einzelner Listenpunkte ändern. Das ging anfangs nicht (und das war mein Problem), mit der geänderten Konstruktion schon.
                                      moveInProgress sperrt eine Liste, bei der gerade eine Positionsänderung in Gang ist, währenddessen kann aber der Änderungsprozess für andere Listen angestoßen werden.

                                      1. Aber wieso sollte es dann funktionieren?

                                        Weil du nur auf eine lokale Variable zugreifst und nicht auf eine Eigenschaft des Objektes.
                                        Versuch ichs mal so:
                                        Du machst folgendes:
                                        <html>
                                          <head>
                                            <title>test</title>
                                          </head>
                                          <body>
                                            <script type="text/javascript">
                                              var xxx = {
                                                xxx: "xxx",
                                                func: function()
                                                {
                                                  alert(this.xxx)
                                                  alert(this.yyy)
                                                }
                                              }
                                              var yyy = {
                                                yyy: "yyy"
                                              };
                                              yyy.func = xxx.func;
                                              yyy.func();
                                            </script>
                                          </body>
                                        </html>
                                        solltest aber das
                                        <html>
                                          <head>
                                            <title>test</title>
                                          </head>
                                          <body>
                                            <script type="text/javascript">
                                              var xxx = {
                                                xxx: "xxx",
                                                func: function()
                                                {
                                                  alert(this.xxx)
                                                  alert(this.yyy)
                                                }
                                              }
                                              var yyy = {
                                                yyy: "yyy"
                                              };
                                              function getFunc(xxx)
                                              {
                                                return function() { xxx.func() };
                                              }
                                              yyy.func = getFunc(xxx);
                                              yyy.func();
                                            </script>
                                          </body>
                                        </html>
                                        machen!

                                        1. Bringen wir mal die lokale Variable noch mit unter, um zu zeigen, dass die immer zugreifbar ist(bei dir noch über eine Closure, aber das ist erst mal egal).
                                          <html>
                                            <head>
                                              <title>test</title>
                                            </head>
                                            <body>
                                              <script type="text/javascript">
                                                var xxx = {
                                                  xxx: "xxx",
                                                  func: function()
                                                  {
                                                    var localVar = "localVar";
                                                    alert(this.xxx);
                                                    alert(this.yyy);
                                                    alert(localVar);
                                                  }
                                                }
                                                var yyy = {
                                                  yyy: "yyy"
                                                };
                                                function getFunc(xxx)
                                                {
                                                  return function() { xxx.func() };
                                                }
                                                yyy.func = xxx.func;
                                                yyy.func();
                                                alert("===jetzt mit Objektbindung===");
                                                yyy.func = getFunc(xxx);
                                                yyy.func();
                                              </script>
                                            </body>
                                          </html>

                                        2. Du machst folgendes:
                                          <html>
                                            <head>
                                              <title>test</title>
                                            </head>
                                            <body>
                                              <script type="text/javascript">
                                                var xxx = {
                                                  xxx: "xxx",
                                                  func: function()
                                                  {
                                                    alert(this.xxx)
                                                    alert(this.yyy)
                                                  }
                                                }
                                                var yyy = {
                                                  yyy: "yyy"
                                                };
                                                yyy.func = xxx.func;
                                                yyy.func();
                                              </script>
                                            </body>
                                          </html>

                                          I'm sorry, aber ich kann dir einfach nicht folgen, weil ich doch das mache:

                                          <html xmlns="http://www.w3.org/1999/xhtml">  
                                            <head>  
                                              <meta charset="utf-8"/>  
                                              <title></title>  
                                            </head>  
                                            <body>  
                                              <!-- ====================== -->  
                                              <ul id="wrapper1" class="changeposul">  
                                                <li id="fd1">a1</li>  
                                                <li id="fd2">a2</li>  
                                                <li id="fd7">a7</li>  
                                              </ul>  
                                              <!-- ====================== -->  
                                              <ul id="wrapper2" class="changeposul">  
                                                <li id="fda">a1</li>  
                                                <li id="fdb">a2</li>  
                                              </ul>  
                                              <!-- ====================== -->  
                                              <script>
                                          
                                            
                                          var MyFW = (function () {  
                                            
                                            function init() {  
                                              var changePosULsArray = document.getElementsByClassName('changeposul');  
                                              for (var y= 0; y < changePosULsArray.length; y++) {  
                                                var liChangePosHandlerLoop = new LiChangePosHandler();  
                                                liChangePosHandlerLoop.init(y);  
                                                changePosULsArray[y].addEventListener("click", liChangePosHandlerLoop.moveUp,  false);  
                                              }  
                                            }  
                                            
                                            return {  
                                              afterLoad: function() {  
                                                init();  
                                              }  
                                            }  
                                            
                                            function LiChangePosHandler() {  
                                            
                                              var moveInProgress;  
                                              var moveCounter;  
                                            
                                              this.init = function (counter) {  
                                                moveInProgress = false;  
                                                moveCounter = counter;  
                                              };  
                                            
                                              this.moveUp = function (eventObject) {  
                                                alert(moveInProgress+"|"+moveCounter);  
                                                if (moveInProgress == false) {  
                                                  moveInProgress = true;  
                                                  // Do anything  
                                                }  
                                              };  
                                            
                                            }  
                                            
                                          })();  
                                          myContentLoaded (window, MyFW.afterLoad ); 
                                          
                                              </script>  
                                            </body>  
                                          </html>
                                          

                                          Da fehlt mir jetzt echt das Wissen um deine Angabe oben mit meiner Angabe unten zu vergleichen.

                                          1. yyy                 => changePosULsArray[y]
                                            yyy.yyy             => eine beliebige Eigenschaft von dem Element welches auf das Event reagiert
                                            xxx.xxx             => eine beliebige Eigenschaft von deinem Objekt welches den Eventhandler implementiert
                                            xxx                 => liChangePosHandlerLoop
                                            xxx.func            => liChangePosHandlerLoop.moveUp
                                            yyy.func = xxx.func => changePosULsArray[y].addEventListener(...)
                                            yyy.func()          => nach click event wird der Handler gerufen

                                            xxx.xxx sollte eigentlich im Eventhandler xxx.func zugänglich sein, da es eine Eigenschaft am selben Objekt ist.

        2. var x = 42; legt eine lokale Variable im aktuellen Objekt an

          Wobei das aktuelle Objekt auch das globale Objekt sein kann.

          1. Hallo 1UnitedPower,

            var x = 42; legt eine lokale Variable im aktuellen Objekt an

            Wobei das aktuelle Objekt auch das globale Objekt sein kann.

            deswegen ja der Zusatz "im aktuellen Objekt". Gleiches gilt für this.

            Gruß, Jürgen

            1. deswegen ja der Zusatz "im aktuellen Objekt". Gleiches gilt für this.

              Habe ich auch so verstanden, ich dachte trotzdem, dass man das nochmal betonen sollte. Die Bedeutung von "aktuell" ist sonst schnell überlesen.

  2. Hallo,

    was ich gesucht habe steht hier bei molily.

    Viele Grüße
    Siri

    1. Hallo Siri,

      was ich gesucht habe steht hier bei molily.

      und was war das? Ist dein Problem jetzt gelöst?

      Gruß, Jürgen

      1. Hallo,

        und was war das?

        Erzeugung von mehreren Instanzen eines Objektes innerhalb eines Scopes mit öffentliche und private Funktionen, die sich Variablen innerhalb der Instanz eines Objektes teilen.

        Ist dein Problem jetzt gelöst?

        Ja, Molily sei Dank! :-)

        Viele Grüße
        Siri