Siri: Frage zur Notation non JavaScripten

Hallo,

gibt es einen signifikanten Unterschied zwischen dieser

var example1 = (function () {  
  
	function test1() {  
	  
		this.test1a = function() {  
		  
		}  
		  
		this.test1b = function() {  
		  
		}  
	}  
})();	  

und dieser

var exapmle2 = {};  
exapmle2.test2 = function() {  
  
	function test2a() {  
	  
	}  
	  
	function test2b() {  
	  
	}	  
}();

Notation? Oder ist das eher eine Geschmacksfrage? Variante zwei scheint irgendwie kompakter...

Viele Grüße
Siri

  1. Hallo,

    deine Codebeispiele machen leider keinen Sinn.

    var example1 = (function () {

    function test1() {

      this.test1a = function() {  
        
      }  
        
      this.test1b = function() {  
        
      }  
    

    }
    })();

      
    Wo wird test1 aufgerufen? Worauf zeigt »this€ in test1? Die sofort ausgeführte Funktion gibt nichts zurück. Was soll sie zurückgeben? Welche Funktionen sollen von außen zugänglich (öffentlich) sein, welche privat?  
      
    
    > ~~~javascript
    
    var exapmle2 = {};  
    
    > exapmle2.test2 = function() {  
    >   
    > 	function test2a() {  
    > 	  
    > 	}  
    > 	  
    > 	function test2b() {  
    > 	  
    > 	}	  
    > }();
    
    

    Wo werden test2a und test2b aufgerufen?

    Bitte beschreibe einmal, was du vorhast, und stelle funktionierende Beispiele zur Verfügung (am besten ohne »example« und »test«).

    Mathias

    1. Hallo,

      Wo wird test1 aufgerufen? Worauf zeigt »this€ in test1? Die sofort ausgeführte Funktion gibt nichts zurück. Was soll sie zurückgeben? Welche Funktionen sollen von außen zugänglich (öffentlich) sein, welche privat?

      Das ganze ist etwas abstrakt (deshalb auch example und test). Letztendlich suche ich eine geeignete Form für eine gekapselte Schreibweise, wobei das eher darauf abzielt, eine Artvon Namespace zu haben, um damit die Skripte übersichtlicher zu organisieren.

      Viele Grüße
      Siri

      In diesem Beispiel muss ich wohl myTest = new test1(); erzeugen?!

      var example1 = (function () {  
        
      	function test1() {	  
      		this.test1a = function() {  
      				return "a";  
      		}  
      		  
      		this.test1b = function() {  
      				return "b";  
      		}  
      	}  
      	  
      	return {  
      		anfrage1: function() {							  
      			myTest = new test1();  
      			return myTest.test1a() + myTest.test1b();  
      		}  
      	}  
      				  
      				  
      })(); 
      
      var exapmle2 = {};  
      exapmle2.test2 = function() {  
        
      	function test2a() {  
      		return  "a";  
      	};  
      	  
      	function test2b() {  
      			return "b";  
      	};	  
      	  
      	return {  
      		anfrage2: function() {  
      			return test2a() + test2b();  
      		}  
      	};  
      }();  
      alert("2:" + exapmle2.test2.anfrage2());
      
      1. var example1 = (function () {

        function test1() {
        this.test1a = function() {
        return "a";
        }

          this.test1b = function() {  
          		return "b";  
          }  
        

        }

        return {
        anfrage1: function() {
        myTest = new test1();
        return myTest.test1a() + myTest.test1b();
        }
        }

        })();

          
        Hier fehlt noch  
        `alert("1:" + example1.anfrage1())`{:.language-javascript}  
        als Aufruf.  
          
        
        > ~~~javascript
        
        var exapmle2 = {};  
        
        > exapmle2.test2 = function() {  
        >   
        > 	function test2a() {  
        > 		return  "a";  
        > 	};  
        > 	  
        > 	function test2b() {  
        > 			return "b";  
        > 	};	  
        > 	  
        > 	return {  
        > 		anfrage2: function() {  
        > 			return test2a() + test2b();  
        > 		}  
        > 	};  
        > }();  
        > alert("2:" + exapmle2.test2.anfrage2());
        
        
      2. Das ganze ist etwas abstrakt (deshalb auch example und test).

        So kann dir leider niemand einen kompetenten Rat geben.

        Letztendlich suche ich eine geeignete Form für eine gekapselte Schreibweise, wobei das eher darauf abzielt, eine Artvon Namespace zu haben, um damit die Skripte übersichtlicher zu organisieren.

        Dafür *kannst* du sofort ausgeführte Funktionen benutzen. Mehr kann man so abstrakt nichts dazu sagen.

        In deinem Beispiel vergleichst du einen Konstruktor mit einer Lösung ohne Konstruktor. Das ist so sinnvoll wie die Frage »Ist ein Flugzeug besser als ein Auto?«, ohne den Anwendungszweck zu spezifizieren. Ich kenne deinen Anwendungszweck nicht.

        Konstruktoren und Prototypen (»Pseudoklassen«) sind etwas anderes als einfache Objekte und geschachtelte Funktionen. Man benutzt sie, um zahlreiche Objekte mit gleichartiger Funktionalität und eigenem State zu erzeugen. Die Definition von Typen und das Erzeugen von Instanzen ist eine wichtige Technik in der objektorientierten Programmierung.

        Ob das nun in deinem Fall sinnvoll ist, lässt sich anhand dieser nichtssagenden Beispiele schwer beantworten.

        Zur allgemeinen Lektüre:
        http://molily.de/js/organisation-module.html
        http://molily.de/js/organisation-instanzen.html
        http://molily.de/weblog/javascript-pseudoklassen

        Mathias

  2. Wenn ich raten müsste, würde ich tippen du willst folgendes:

    var example1 = (function () {  
      
     	function test1() {  
     	  
     		this.test1a = function() {  
     		  
     		}  
     		  
     		this.test1b = function() {  
     		  
     		}  
     	}  
            return new test1();  
     })();	  
    
    

    ~~~javascript

    var exapmle2 = (function() {

    function test2a() {
     
      }
     
      function test2b() {
     
      }

    return {
              test2a = test2a,
              test2b = test2b,
            }
     })();

      
    \* Da du die Funktionen ja an ein Objekt bindest willst du dann sicher auch auf Objekteigenschaften mit this zugreifen. Das finde ich in Version 2 nicht gut, da die Funktionen erst mal keinen ersichtlichen Kontext besitzen.  
    \* Du willst nur 1 Objekt erzeugen. Dann benötigst du eigentlich keinen Konstruktor.  
      
     ~~~javascript
      
     var exapmle3 = (function() {  
            return {  
              test3a = function() {  
     	  
     	  },  
              test3b = function() {  
     	  
     	  }  
            }  
     })();
    
    1. Die Kapselung macht natürlich auch nur Sinn, wenn es noch was zu kapseln gibt, sonst kann man auch gleich

        
        var exapmle3 = {  
                 test3a: function() {  
        	  
        	  },  
                 test3b: function() {  
        	  
        	  }  
        
        };
      

      schreiben.

    2. Hallo,

      ich hab das im ersten Anlauf schlecht beschrieben. Wenn man in einer Sache so drinsteckt...

      In meiner Antwort an molily wird (hoffentlich) klarer, worauf ich abziele.

      Viele Grüße
      Siri

      1. Letztendlich suche ich eine geeignete Form für eine gekapselte Schreibweise, wobei das eher darauf abzielt, eine Artvon Namespace zu haben, um damit die Skripte übersichtlicher zu organisieren.

        Naja, Namespaces sind ja nicht dafür gedacht Skripte zu organisieren und übersichtlicher zu gestalten. Wobei man durch geeignete Objektierung und Kapselung schon die Übersicht erhöht.
        Was ich sagen will, es reicht nicht um einen Codeteil einfach einen Block zu legen.

        Dein 1. Beispiel macht so wie es ist nicht so viel Sinn. Die Memberfunktionen haben keinen Bezug zum Objekt.
        Hier würde man auf jeden Fall die Anfrage schon dem Objekt zuordnen.
        this.anfrage = function(){
          return this.test1a() + this.test1b();
        }
        Wenn test1a() und test1b() nicht sichtbar sein sollen, der Objektbezug aber auch nicht benötigt wird, kannst du die auch als lokale Funktionen im Konstruktor anlegen.
        function test1() {
          function test1a() {
            return "a";
          }
          function test1b() {
            return "b";
          }
          this.anfrage = function(){
            return test1a() + test1b();
          }
        }
        Dann benötigst du hier aber wieder die Kapselfunktion nicht, es ist ja alles schon gekapselt.
        Dann kannst du aber mehrere Instanzen von test1 anlegen. Willst du das nicht, kannst du es so machen wie in deinem 2. Beispiel.

  3. @molily & @unknown

    Hallo,

    vielen Dank für eure Einschätzungen und Anregungen! Jetzt ist mir zumindest klar geworden, dass ich versucht habe, das Pferd von hinten aufzuzäumen. Ich hätte mit der eigentlichen Problemstellung anfangen sollen. Ich dachte, ich muss nur noch meine Lösungsansätze abwägen...

    Also: Ich arbeite mit einem Framework (gesetzt durch den Auftraggeber) bei dem einzelne HTML-Seiten über xml-Dateien definiert werden. Dabei kann es auch zu inhlatlichen Seitenkonglomeraten(Gruppe) in Form von Tabs und Untertabs kommen. Einzlne Seiten müssen dann bestimmte Funktionalitäten bekommen, auf Klicks reagieren etc. Es wird dann eine Businesslogik angestoßen, die je nach dem per AJAX an den Server zur Verarbeitung geschickt werden, andere Dinge werden per JS an der "Oberfläche" abgearbeitet.
    Es gibt also drei Arten von JS-Kategorien:

    1. Allgemeingültige JS für alle Seiten/Gruppen
    2. JS für eine bestimmte Gruppe
    3. JS, die nur auf einer bestimmten Seite Verwendung finden

    Da ich bei Problemen oder Erweiterungen vom generierten HTML wieder rüchwärts zu den einzelnen XML-Seiten(die ich auf Browsereben nicht mehr sehe) und ihren Komponenten (zugeordneten JS) schließen muss, wäre ein Aufruf von JS-Funktionen/Methoden in der Art nicht schlecht:

    1. Allgemeingültige JS für alle Seiten/Gruppen
    Common.Domhelper.toggleButton();
    Common.Ajax.getXYData();

    2. JS für eine bestimmte Gruppe
    Object.Handlecontrols.getABCId();
    Object.States.getObjectState()

    3. JS, die nur auf einer bestimmten Seite Verwendung finden
    ObjectPart.Calculation.getMonthRate();
    ObjectPart.ButtonStates.setButtonDisabled("buttonid");

    Das hätte für mich den Vorteil, das ich dann, wenn alles zusammengeneriert wird, sofort erkennen kann, wo die entsprechende Funktionalität steckt.
    Common -> common.js
    Common.Domhelper -> Gruppe von JS-Functions im Bereich Domhelper ( "Domhelper = function(){}" )
    Common.Domhelper.toggleButton(); -> Die benütigte "Methode" in dieser Gruppe in der JS common.js

    Sowas würde mir ungemein helfen, die Arbeit zu organisieren und zu strukturieren. Jetzt also die tatsächliche Frage: Was ist dafür die geeignete JS-Struktur/Architektur? Die Methoden sind überwiegend "statischer" Natur, abundzu macht es sicher Sinn ein Art von Objekten für bestimmte Zustände von "Gruppen" vor zu halten.

    Viele Grüße
    Siri

    1. Es gibt also drei Arten von JS-Kategorien:

      1. Allgemeingültige JS für alle Seiten/Gruppen
      2. JS für eine bestimmte Gruppe
      3. JS, die nur auf einer bestimmten Seite Verwendung finden

      Vielleicht habe ich das auch falsch verstanden, aber ich würde das nach Funktionalität aufteilen und nicht nach Verwendung.

      1. Allgemeingültige JS für alle Seiten/Gruppen
        Common.Domhelper.toggleButton();
        Common.Ajax.getXYData();

      Ja, das klingt gut.

      1. JS für eine bestimmte Gruppe
        Object.Handlecontrols.getABCId();
        Object.States.getObjectState()

      Hmm, das verstehe ich schon nicht mehr, getObjectState() würde ich am jeweiligem Objekt erwarten und nicht einem Statesobjekt zuordnen.
      Oder verwaltet dein Object (schlechter Name) mehrere Objekte und über Object.States willst du einen Zugriff auf die States aller Objekte anbieten?

      1. JS, die nur auf einer bestimmten Seite Verwendung finden
        ObjectPart.Calculation.getMonthRate();
        ObjectPart.ButtonStates.setButtonDisabled("buttonid");

      Die Domhelperfunction (wenn ich es richtig verstanden habe) setButtonDisabled würde ich auch dort hinstecken, egal ob sie immer verwendet wird oder nicht.

      Jetzt also die tatsächliche Frage: Was ist dafür die geeignete JS-Struktur/Architektur?

      Die hast du doch selbst vorgegeben?

      var Common = (function() {

      var Domhelper = {
          toggleButton: function() {
          }
        };

      var Ajax = {
          getXYData: function() {
          }
        };

      return {
          Domhelper: Domhelper,
          Ajax: Ajax
        };
      }();

      1. Hallo,

        Jetzt also die tatsächliche Frage: Was ist dafür die geeignete JS-Struktur/Architektur?
        Die hast du doch selbst vorgegeben?

        var Common = (function() {  
          
           var Domhelper = {  
             toggleButton: function() {  
             }  
           };  
          
           var Ajax = {  
             getXYData: function() {  
             }  
           };  
          
           return {  
             Domhelper: Domhelper,  
             Ajax: Ajax  
           };  
         })();
        

        Super! Da wollte ich hin! Vielen Dank!

        Viele Grüße
        Siri

      2. Hallo,

        noch eine Nachfrage.

        var Common = (function() {  
          
           var Domhelper = {  
             toggleButton: function() {  
             }  
           };  
          
           var Ajax = {  
             getXYData: function() {  
             }  
           };  
          
           return {  
             Domhelper: Domhelper,  
             Ajax: Ajax  
           };  
         })();
        

        Ich hab wohl keine Chance auf der Ebene "toggleButton" eine private "Methode zu deklarieren?

        var Domhelper = {  
             toggleButton: function() {  
             }  
             this.nurInnerhalbDomHelperErrichbar: function() {  
             }  
        }
        

        ist an der Stelle nicht zulässig.

        Viele Grüße
        Siri

        1. Hallo,

          Siehe http://molily.de/js/organisation-module.html – hatte ich schon verlinkt. Älterer Überblickartikel: http://aktuell.de.selfhtml.org/artikel/javascript/organisation/

          var Domhelper = {

          toggleButton: function() {
               }
               this.nurInnerhalbDomHelperErrichbar: function() {
               }
          }

            
          ~~~javascript
          var RevealingModulePattern = (function() {  
            
            // Vorerst private Funktionen  
            var foo = function() {};  
            var bar = function() {  
              foo();  
            };  
            
            // Öffentliche Schnittstelle  
            return {  
              bar: bar  
            };  
            
          })();
          

          foo ist privat, bar ist öffentlich.

          Mathias

        2. var Common = (function() {
             function nurInnerhalbDerKapselFuncErrichbar(){

          }
             var Domhelper = {
               toggleButton: function() {
                 nurInnerhalbDerKapselFuncErrichbar();
               }
             };

          var Ajax = {
               getXYData: function() {
               }
             };

          return {
               Domhelper: Domhelper,
               Ajax: Ajax
             };
          })();

          sonst

          var Common = {};

          (function(parent) {
             function nurFürDomhelperErrichbar(){

          }
             parent.Domhelper = {
               toggleButton: function() {
                 nurInnerhalbDerKapselFuncErrichbar();
               }
             };
          })(Common);

          (function(parent) {
             parent.Ajax = {
               getXYData: function() {
               }
             };
          })(Common);

    2. Hallo,

      Im Allgemeinen halte ich folgende Architektur für sinnvoll:

      • OOP mit Konstruktoren und Instanzen, d.h. Nutzung von prototypische Delegation
      • Singletons vermeiden
      • Model-View-Controller mit Trennung von Daten- und DOM-Logik
      • Durch Routing wird JavaScript-Code für bestimmte Seiten ausgeführt (das Kriterium kann die URL sein oder das DOM)
      • Modularisierung mit AMD-, Common.js- oder ECMAScript-6-Modulen
      • Größtmögliche Kapselung, sodass idealerweise keine Objekte global erreichbar sind
      • Sinnvolle Speicherbereinigung – Objekte werden geordnet abgebaut und ihre Referenzen entfernt, wenn der zugehörige UI-Kontext verlassen wird

      Diese Regeln gelten für größere JavaScript-Anwendungen, sind aber auch für mit etwas JavaScript angereicherte Seiten hilfreich. Viele Pattern der obigen Liste werden von einfachen Bibliotheken wie Backbone.js oder Can.js abgedeckt.

      1. Allgemeingültige JS für alle Seiten/Gruppen
        Common.Domhelper.toggleButton();

      Ein Button wäre aus OOP-Sicht auch nur eine weitere Interfacekomponente. Solche Logik gehört in eine View-Klasse oder ein darin verfügbaren DOM-Toolkit.

      Falls es ein DOM-Toolkit ist, so würde ich mir eine bessere API überlegen. Eine jQuery-/Zepto-/DOMAssistant-artige hat sich hier durchgesetzt. Falls irgendwann ein anderer daran arbeiten soll, würde ich definitiv für jQuery votieren.

      Common.Ajax.getXYData();

      Solche Logik gehört in eine Model-Klasse oder, falls es sich um einen generischen HTTP-Adapter handelt, in eine Service-Klasse.

      1. JS für eine bestimmte Gruppe
        Object.Handlecontrols.getABCId();

      Sieht nach View-Logik aus.

      Object.States.getObjectState()

      Sieht nach Model-Logik aus.

      1. JS, die nur auf einer bestimmten Seite Verwendung finden
        ObjectPart.Calculation.getMonthRate();

      Sieht nach einer Service-Klasse aus, die idealerweise rein funktional arbeitet (ohne Zustände, ohne Nebenwirkungen). Ansonsten ist es eine einfache Klasse mit Eingabewerten und Methoden.

      ObjectPart.ButtonStates.setButtonDisabled("buttonid");

      Wieder ein Fall für eine Button-View-Klasse.

      Das hätte für mich den Vorteil, das ich dann, wenn alles zusammengeneriert wird, sofort erkennen kann, wo die entsprechende Funktionalität steckt.

      Dafür sind eher Modulformate gedacht. AMD, Common.js oder ECMAScript-6-Module, welche man zu ECMAScript 5 »transpilieren« kann. So kann man den Code sinnvoll in Dateien aufteilen und sie in einer Weise verbinden, dass die Abhängigkeiten ersichtlich (und maschinenlesbar) sind.

      Die Methoden sind überwiegend "statischer" Natur, abundzu macht es sicher Sinn ein Art von Objekten für bestimmte Zustände von "Gruppen" vor zu halten.

      Das ist m.E. das Problem. Ich würde dagegen votieren, für alles statische Methoden anzulegen. Klassen sind besser automatisiert testbar und eignen sich besser, um Zustände zu speichern, Funktionalität zu kapseln und Code wiederzuverwenden.

      Grüße,
      Mathias

      1. Hallo,

        vielen Dank! Das muss ich jetzt erstmal verdauen und mich neu sortieren.

        Viele Grüße
        Siri