Felix Riesterer: JavaScript

Beitrag lesen

Lieber ROGA,

Ich fange langsam an, das Konstrukt zu verstehen und habe gerade für mich gedacht: "Ja, so macht das erstellen eines Objekts Sinn, so möchte ich es bauen" und du schreibst dann:

:-) Fortschritt!

Spätestens jetzt wird die Sache unübersichtlich.

Für mich macht das Objekt in deinem Beispiel so absolut Sinn und ich würde es auch so bauen wollen. Sehe ich hier einfach nicht über den Tellerrand hinaus?

Damit meinte ich nicht das Objekt selbst, sondern den Code. Um eine Objektstruktur dieser Art zu bauen, würde ich gerne die Struktur des Batterie-Objektes als eigenständiges Stück Code haben wollen, welches nur die Batterie selbst beschreibt. Ihre Eigenschaften (Werte) und Methoden (Funktionen). Das Zusammenfügen zum PV-Objekt bedient sich dann an diesem Code.

Beispiel mit der class-Schreibweise:

class Batterie {

  constructor (index) {
    this.index = index;
  }

  loadData () {
    this.Status = getState('sun2000.' + this.index + '.collected.SOC').val;
    this.LadungEntladung = getState('sun2000.' + this.index + '.collected.chargeDischargePower').val;
  }

  index = 0;
  Status = null;
  LadungEntladung = null;
}

class PVA {

  Batterie = null;
  QuatschMitSosse = null;

  update () {
   Object.keys(this).forEach(name => {
     if ("function" == typeof this[name].loadData) {
       this[name].loadData();
     }
   });
  }
}

const myPVA = new PVA();
myPVA.Batterie = new Batterie(0); // 0 bedeutet sun2000.0 für erste Batterie

Hier werden zwei Klassen definiert, in denen die Blaupause für das jeweilige Objekt stehen. Mit dem Schlüsselwort new kann damit eine neue Objektinstanz erzeugt werden (siehe letzte beiden Zeilen). Anstatt das verschachtelte Gesamt-Objekt PV zu notieren, werden hier nur die jeweiligen Einzelobjekte definiert, um sie am Ende zusammenzusetzen. Das kann die Übersicht erhöhen.

 // Methode zum Aktualisieren der Daten in den Unterobjekten
 update: function () {
   Object.keys(this).forEach(name => {

Hier beiss ich mir an deinem Beispiel gerade die Zähne aus.

Das war zu erwarten. Hier habe ich zu viel Abstraktion auf einmal auf Dich geworfen. Mal sehen, ob wir zumindest einen Teil verstanden bekommen.

Die Methode "update" ruft eine Funktion ohne Namen auf "update: function()".

Jein. Das Objekt hat eine Methode update, die ihren Code nach dem Doppelpunkt notiert bekommt. Vergleiche diese Schreibweisen:

function tuWas (param) {
  console.log(param);
}

const tuWasAnderes = function (param) {
  console.log(param);
}; // mit abschließendem Semikolon

const myTuWas = tuWas;
const myTuWasWert = tuWas(); // undefined

Das erste Beispiel sollte klar sein: Es wird eine Funktion namentlich definiert, weil da „einfach so“ ein Funktionsliteral steht.

Das zweite Beispiel definiert eine Konstante namens tuWasAnderes, die einen Wert zugewiesen bekommt. Dieser Wert ist als Funktionsliteral geschrieben, welches eine anonyme Funktion darstellt. Damit wird die Konstante tuWasAnderes zu einer Funktion.

Das dritte Beispiel ist ebenso eine Wertzuweisung wie das zweite Beispiel, nur dass hier eine bereits definierte Funktion als Wert zugewiesen wird. Ab dem Moment kann man tuwas() und myTuWas() synonym verwenden.

Das vierte Beispiel soll den Unterschied zwischen der Zuweisung einer Funktion selbst und der Zuweisung ihres Rückgabewerts zeigen. Wenn man myTuWas aufruft, gibt sie keinen Wert zurück, weshalb myTuWasWert ein undefined enthält.

Im Objektliteral, in dem update: function () { ... } steht, steht im Grunde eine Wertzuweisung, wie im zweiten Beispiel mit der Konstante tuWasAnderes.

Dann folgt der Konstrukt dieser Funktion worin ein Objekt aufgerufen wird, das die Methode ForEach() besitzt -> "Object.keys(this).forEach()". Sollte ich das soweit richtig interpretiert haben, so habe ich es leider noch nicht entschlüsseln können, was "Object.keys() genau macht.

Hier gehen wir ein bisschen auf die Meta-Ebene der Programmierung. Object.keys() liefert die Namen aller Eigenschaften und Methoden eines Objektes zurück, also alles das, was bei der Schreibweise als Objektliteral vor den Doppelpunkten gestanden hat. Diese Liste liefert es als Liste in Form des Datentyps Array zurück. Ein Array ist natürlich auch wieder ein Objekt, weil alles in JavaScript ein Objekt ist. Um nun an die Elemente darin einzeln heranzukommen, kann man entweder eine Schleife schreiben (z.B. eine for-Schleife), oder man verwendet die Array-Methode forEach dafür, die als Parameter eine weitere Funktion haben will, die dann ihrerseits das Element zur Verarbeitung bekommt.

Die Pfeilfunktion ist eine anonyme Funktion, die einen Parameter in der Variable name aufnimmt. In unserem Beispiel bekommt sie als Wert den Namen einer Eigenschaft oder Methode unseres PVA-Objekts. Diese Eigenschaft wird darauf untersucht, ob ihre loadData-Eigenschaft vom Typ function ist. Wenn es keine solche gibt, ist der Datentyp dann undefined. Handelt es sich aber um den Datentyp function, ist es eine Methode und wird dann sofort ausgeführt.

An dieser Stelle verwende ich deshalb eine Pfeilfunktion, weil sie die Bedeutung von this nicht ändert.

Ich erahne nur, dass hier möglicherweise mit "this" (was geschätzt wohl das Objekt PVA repräsentiert) das gesamte PVA-Objekt nach Methoden mit der Bezeichnung "loadData" durchsucht wird.

Das schlüsselwort this verweist immer auf das Objekt, in dessen Kontext eine Methode aufgerufen wurde. In diesem Fall ist das in der Tat das PVA-Objekt. Aber nicht dessen Methoden werden auf loadData geprüft, sondern ob dessen Eigenschaften eine solche Methode besitzen, weil sie selbst Objekte mit Methoden sind.

Wenn eine solche Methode gefunden wurde, wird diese dann mittels this[name].loadData() aufgerufen und somit ausgeführt. Aber wirklich sicher bin ich mir hier nicht.

Das ist genau richtig. Wenn ich den Namen einer Eigenschaft in einer Variable stehen habe, dann kann ich nicht die Punkt-Schreibweise verwenden, sondern muss die eckigen Klammern um die Variable schreiben:

const name = "Status";

PVA.Batterie.Status = 1;
PVA.Batterie[name] = 2;
PVA.Batterie.name = 3;

console.log(PVA.Batterie.Stats); // 2

Die letzte Wertzuweisung erzeugt in obigem Beispiel eine neue Eigenschaft für das PVA-Objekt, die den Namen „name“ trägt und den Wert 3 zugewiesen bekommt.

Hilft Dir das weiter?

Liebe Grüße

Felix Riesterer