diff --git a/src/components/slides/javascript/02-complex-datatypes/arrays.astro b/src/components/slides/javascript/02-complex-datatypes/arrays.astro
new file mode 100644
index 0000000..3b43b66
--- /dev/null
+++ b/src/components/slides/javascript/02-complex-datatypes/arrays.astro
@@ -0,0 +1,173 @@
+ Arrays sind ähnlich zu Objekten komplexe Objekte die im Heap allokiert werden. Arrays können beliebig viele Daten beinhalten und haben keine feste Größe. (Es können aber Arrays mit einer bestimmten Länge initialisiert werden.) Die Inhalte eines Arrays können beliebig sein. Die Länge eines Arrays steht in der Property "length" Aus persönlicher Sicht sind Arrays der alltäglichste Datentyp mit dem man Arbeiten wird. .every() Prüft, ob jedes Element im Array einer gegebenen Prüfung standhält. Nur .filter() Prüft alle Elemente eines Arrays. Die Elemente die die Prüfung bestehen, werden in einem neuen Array zurück gegeben. Das originalle Array wird nicht modifiziert. .find() Prüft die Elemente eines Arrays. Das erste Element, dass die Prüfung besteht wird zurück gegeben. Es existiert eine alternative Methode .findIndex(), die Funktion liefert den Index des Elementes anstatt das Elementes selbst das gefunden wurde. .includes() Prüft ob im Array ein gesuchtes Element vorhanden ist. Aufgrund der Art wie Elemente gespeichert werden, sollte darauf geachtet werden das es zu ungewollten Problemen mit komplexen Datentypen kommen kann. .map() Erzeugt ein neues Array. Jedes Element wird in einer Funktion modifiziert und in ein neues Array gepackt. Das alte Array bleibt unberührt. push & pop Modifiziert das Array in dem es Elemente am Ende mit Bei der .reduce() Kalkuliert einen Wert basierend aus den Elementen des Array. Das Array erwartet 2 Werte: eine Funktion in der ein Accumulator und der aktuelle Wert als Parameter übergeben wird und den nächsten Wert zurück geben soll. Und den initialen Wert das Accumulators. some Prüft ob mindestens ein Element des Arrays die Prüfung besteht. Wenn das nicht der Fall ist wird ein .sort() Sortiert das Array "In Place" (Ursprüngliches Array wird modifiziert). Hierzu führt Arrays
+
+
+ const arr = [5, '42', false, {}, [], undefined, null];
+
+
+ const arr = [1,2,3,4,5];
+
+ // 5
+ console.log(arr.length);
+
+
+ Array-Funktionen
+
+
+ const arr = [15, 25, 765, 11];
+
+ // true
+ console.log(arr.every((value) => value > 10));
+
true
wenn alle Elemente dem Test bestehen.
+
+ const arr = [5, 24, 1, 9, 22];
+
+ // [24, 22]
+ console.log(arr.filter((value) => value > 10));
+
+
+ const arr = [5, 24, 1, 9, 22];
+
+ // 24
+ console.log(arr.find((value) => value > 10));
+
+
+ const arr = [5, 24, 1, 9, 22];
+
+ // true
+ console.log(arr.includes(22));
+
+
+ const obj = {};
+ const arr = [obj];
+
+ // true
+ console.log(arr.includes(obj));
+
+ // false
+ console.log(arr.includes({}));
+
+
+ const arr = [1, 2, 3, 4, 5];
+
+ // [1, 4, 9, 16, 25]
+ console.log(arr.map((value) => value * value));
+
+
+ const arr = [1, 2, 3];
+ arr.push(4);
+
+ // [1, 2, 3, 4]
+ console.log(arr);
+
+ // 4
+ console.log(arr.pop());
+
+ // [1, 2, 3]
+ console.log(arr);
+
push
hinzufügt, und mit pop
aus dem Ende heraus nimmt.pop
-Funktion wird das entfernte Element zurück gegeben.
+
+ const arr = [1,2,3,4];
+
+ // 10
+ console.log(arr.reduce((acc, val) => {
+ acc += val;
+ }, 0));
+
+
+ const arr = [1, 5, 10, 25];
+
+ // true
+ console.log(arr.some((value) => value > 10));
+
false
zurück gegeben.
+
+ const arr = [1, 10, 5];
+
+ a.sort((a, b) => a - b);
+
+ // [1, 5, 10]
+ console.log(a);
+
sort
eine Funktion aus, die mitgegeben wird. Anhand des Ergebnisses werden Elemente im Array umsortiert
+
+
Objekte in JS sind eine der wichtigstens Grundpfeiler, die die Sprache so mächtig machen.
+In JavaScript ist das Objekt das alles Abbildet (in Fakt, alles in JavaScript ist ein Objekt, auch die anderen Datentypen).
+Anders als bei Sprachen mit strikten Datentypen (und Klassen die eine fest Vorgegebene Struktur aufweisen), kann ein Objekt in JavaScript dynamisch erstellt und modifiziert werden.
+Objekte kommen am einem Key-Value-Speicher an nahesten. Ein Key kann dabei ein beliebiger string sein, der Wert kann alles annehmen.
+Ein Objekt wird einfach mit Geschweiften (Curly) Klammern definiert.
+
+ const meinObjekt = {
+ key: "value",
+ numeric: 5,
+ boolean: false,
+ }
+
+ Objekte können auch ineinander geschachtelt werden (in beliebiger Tiefe)
+
+ const geschachtelt = {
+ level1: {
+ level2: {
+ level3: {
+ level4: "Und so weiter...",
+ },
+ },
+ },
+ };
+
+ Auch wenn JS diese Flexibilität bietet, sollte die Datenstruktur möglichst flach gehalten werden.
+Spätestens im Backend muss dieselbe Datenstruktur aufgebaut werden. Falls nicht eine dynamische Sprache wie JS verwendet ist, haben tief geschachtelte Objekte einen großen Mehraufwand im Backend.
+Zugriffe auf Inhalte in einem Objekt können über 2 Wege erreicht werden
+
+ const obj = {
+ value: 5,
+ nested: {
+ value: 42,
+ },
+ };
+
+ // Dot-Notation
+ console.log(obj.nested.value);
+
+ // Array-Like-Access
+ console.log(obj['nested']['value']);
+
+ Gängig ist die Verwendung der dot-notation, hier ist aber das Wissen der keys zur Entwicklungszeit notwendig.
+Wenn programmatisch auf die Inhalte Zugegriffen werden soll, kann dies nur über die Array-Notation geschehen.
+Zusätzlich ist die Array-Notation notwendig, wenn Zeichen verwendet werden, die bereits eine andere Verwendung haben (Beispiel "-", " ")
+
+ const obj = {
+ value: 42;
+ "with-minus": "",
+ };
+
+ console.log(obj['with-minus']);
+
+ // error: console.log(obj.with-minus);
+
+ const key = 'with-minus';
+ console.log(obj[key]);
+
+ Inhalte in Objekten können auch beliebig geändert werden
+
+ const obj = {
+ value: 5,
+ };
+
+ obj.value = 42;
+
+ console.log(obj.value);
+
+ Unstimmigkeit gefunden?
+obj
wurde mit const initialisiert, dessen Inhalt kann aber manipuliert werden.
Mein Fehler? Nein. Das ist JavaScript und seine Komplexen Datentypen funktionieren so.
+Wir müssen nun erstmal verstehen was der Unterschied zwischen simplen und komplexen Datentypen ist, und was das für Folgen hat.
+JavaScript speichert simple Datentypen wie Zahlen oder Strings in Stack ähnlichen Speicher.
+Komplexe Objekte werden im Heap allokiert.
+Das alles ist eine vereinfachte Darstellung. Die internen Vorgänge sind viel komplexer und für den Alltag eines Web-Developers auch nicht notwendig.
+Kurzer Recap: Heap vs Stack
+Inhalte im Stack sind direkt erreichbar und bilden einen LIFO-Speicher (Last-In-First-Out). Die Daten müssen eine Feste Größe haben, zum Vorteil eines schnellen Zugriffs.
+Der Heap stellt einen größeren Speicherbereich da, in dem Inhalte dynamisch abgelegt werden können.
+Im Heap können dynamische / komplexe Datenstrukturen mittels einer Speicherreferenz verwendet werden.
+Was steht "im Hintergrund" nun in der Variable, wenn ein Objekt initialisiert wird?
+Antwort: Ein "Flag" sowie eine Speicherreferenz zum Objekt. Das Flag gibt hierbei an, ob der Wert direkt in der Variable "steckt" oder im Heap mittels der Speicheradresse gefunden werden kann.
+Als Entwickler hat man in JS keine Handhabe darüber, wo die Werte gespeichert werden. Diese Komplexität wird über die darunter liegende JavaScript-Engine abstrahiert.
+Fassen wir zusammen: Komplexe Objekte werden im Heap allokiert, die Variable die den Wert hält ist eigentlich nur ein Pointer zur Speicheradresse im Heap.
+Ändern wir nun eine Eigenschaft im Objekt (Property), ändern wir den Wert im Heap. Die Adresse im Stack bleibt gleich.
+Und hier liegt der Punkt: Der Wert im Stack wird nicht modifiziert, entsprechend bleibt der Wert "konstant" und stellt keine Verletzung der const
Bedingung aus.
Weitere Besonderheiten mit der Speicherbelegung von Objekten
+Wenn ein Objekt aus einem anderen Objekt generiert wird, erfolgt kein Deep-Copy.
+In der Realität geschieht ein copy-by-reference.
+
+ const obj = {};
+ const otherObj = obj;
+
+ // true
+ console.log(obj === otherObj);
+
+ Nun ist wichtig zu beobachten, was passiert wenn wir das Objekt an einer beliegen Variable ändern:
+
+ const obj = {};
+ const otherObj = obj;
+
+ obj.value = 42;
+
+ // 42
+ console.log(otherObj.value);
+
+ Durch diese beiden Beispiele wird nochmals eindeutig, dass wir bei der Handhabung von Objekten genau darauf achten müssen, was wir machen.
+Moderne Frameworks verwenden diese Konzepte für die eigene Datenhaltung. Hier kann es bei nichtbeachtung der "Regeln" zu ungewollten Problemen kommen.
+Sollte es notwendig sein ein Objekt "read-only" zu machen, nutzen Sie Object.freeze(objectToFreeze)
+ const myObject = { value: 5 };
+ Object.freeze(myObject);
+
+ // Erzeugt einen Error
+ myObject.value = 42;
+
+ Obwohl es Sinnvoll sein kann, wird Object.freeze()
recht selten eingesetzt.
Objekte können auch ohne Probleme erweitert werden:
+
+ const obj = {
+ value: 5,
+ };
+
+ // Neue Property mit Namen "type"
+ obj.type = "number";
+
+ Sobald eine Property definiert ist, existiert sie im Objekt, auch wenn diese auf undefined
gesetzt wird.
+ const obj = { value: 5, type: "number" };
+ obj.type = undefined;
+
+ console.log(obj);
+ // Object { value: 5, type: undefined };
+
+ Soll eine Property wirklich entfernt werden, kann man dies mit dem delete
keyword bewerkstelligen.
+ const obj = { value: 5, type: "number" };
+ delete obj.type
+
+ console.log(obj);
+ // Object { value: 5 };
+
+ Wir haben die Möglichkeit, die keys, die values oder beide in ein Array zu konvertieren um darüber zu iterieren und Operationen auszuführen.
+
+ const obj = { value: 5 };
+
+ // ['value']
+ console.log(Object.keys(obj));
+
+ // [5]
+ console.log(Object.values(obj));
+
+ // [['value', 5]];
+ console.log(Object.entries(obj));
+
+ Um zu prüfen, ob ein Objekt ein Property hat, nutzt man die Funktion Object.hasOwn
+ const obj = { value: 5 };
+
+ // true
+ console.log(Object.hasOwn(obj, 'value'));
+ // false
+ console.log(Object.hasOwn(obj, 'other'));
+
+