Frage zur Notation non JavaScripten
Siri
- javascript
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
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
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());
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());
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
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() {
}
}
})();
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.
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
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.
@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
Es gibt also drei Arten von JS-Kategorien:
- Allgemeingültige JS für alle Seiten/Gruppen
- JS für eine bestimmte Gruppe
- 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.
- Allgemeingültige JS für alle Seiten/Gruppen
Common.Domhelper.toggleButton();
Common.Ajax.getXYData();
Ja, das klingt gut.
- 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?
- 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
};
}();
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
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
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
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);
Hallo,
Im Allgemeinen halte ich folgende Architektur für sinnvoll:
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.
- 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.
- JS für eine bestimmte Gruppe
Object.Handlecontrols.getABCId();
Sieht nach View-Logik aus.
Object.States.getObjectState()
Sieht nach Model-Logik aus.
- 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
Hallo,
vielen Dank! Das muss ich jetzt erstmal verdauen und mich neu sortieren.
Viele Grüße
Siri