From 44d5becbd180e02481f41b195373c0e663eedbc3 Mon Sep 17 00:00:00 2001 From: Denis Ergin Date: Wed, 11 Dec 2024 11:29:47 +0100 Subject: [PATCH] feat(slides): add slides for complex-datatypes --- .../02-complex-datatypes/arrays.astro | 173 ++++++++++++ .../02-complex-datatypes/index.astro | 11 + .../02-complex-datatypes/objects.astro | 248 ++++++++++++++++++ .../02-complex-datatypes/title.astro | 3 + .../javascript/02-complex-datatypes.astro | 8 + 5 files changed, 443 insertions(+) create mode 100644 src/components/slides/javascript/02-complex-datatypes/arrays.astro create mode 100644 src/components/slides/javascript/02-complex-datatypes/index.astro create mode 100644 src/components/slides/javascript/02-complex-datatypes/objects.astro create mode 100644 src/components/slides/javascript/02-complex-datatypes/title.astro create mode 100644 src/pages/slides/javascript/02-complex-datatypes.astro 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

+
+ +
+

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.

+
+ +
+

+      const arr = [5, '42', false, {}, [], undefined, null];
+    
+
+ +
+

Die Länge eines Arrays steht in der Property "length"

+

+      const arr = [1,2,3,4,5];
+
+      // 5
+      console.log(arr.length);
+    
+
+ +
+

Aus persönlicher Sicht sind Arrays der alltäglichste Datentyp mit dem man Arbeiten wird.

+
    +
  • Liste an Blogeinträgen zum Anzeigen
  • +
  • Inhalte eines Blogeintrages
  • +
  • Produktlisten
  • +
  • Menüeintrage
  • +
+
+ +
+

Array-Funktionen

+
+ + +
+

.every()

+

+      const arr = [15, 25, 765, 11];
+
+      // true
+      console.log(arr.every((value) => value > 10));
+    
+

Prüft, ob jedes Element im Array einer gegebenen Prüfung standhält. Nur true wenn alle Elemente dem Test bestehen.

+
+ +
+

.filter()

+

+      const arr = [5, 24, 1, 9, 22];
+
+      // [24, 22]
+      console.log(arr.filter((value) => value > 10));
+    
+

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()

+

+      const arr = [5, 24, 1, 9, 22];
+
+      // 24
+      console.log(arr.find((value) => value > 10));
+    
+

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()

+

+      const arr = [5, 24, 1, 9, 22];
+
+      // true
+      console.log(arr.includes(22));
+    
+

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.

+
+ +
+

+      const obj = {};
+      const arr = [obj];
+
+      // true
+      console.log(arr.includes(obj));
+      
+      // false
+      console.log(arr.includes({}));
+    
+
+ +
+

.map()

+

+      const arr = [1, 2, 3, 4, 5];
+
+      // [1, 4, 9, 16, 25]
+      console.log(arr.map((value) => value * value));
+    
+

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

+

+      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);
+    
+

Modifiziert das Array in dem es Elemente am Ende mit push hinzufügt, und mit pop aus dem Ende heraus nimmt.

+

Bei der pop-Funktion wird das entfernte Element zurück gegeben.

+
+ +
+

.reduce()

+

+      const arr = [1,2,3,4];
+
+      // 10
+      console.log(arr.reduce((acc, val) => {
+        acc += val;
+      }, 0));
+    
+

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

+

+      const arr = [1, 5, 10, 25];
+
+      // true
+      console.log(arr.some((value) => value > 10));
+    
+

Prüft ob mindestens ein Element des Arrays die Prüfung besteht. Wenn das nicht der Fall ist wird ein false zurück gegeben.

+
+ +
+

.sort()

+

+      const arr = [1, 10, 5];
+
+      a.sort((a, b) => a - b);
+
+      // [1, 5, 10]
+      console.log(a);
+    
+

Sortiert das Array "In Place" (Ursprüngliches Array wird modifiziert).

+

Hierzu führt sort eine Funktion aus, die mitgegeben wird. Anhand des Ergebnisses werden Elemente im Array umsortiert

+
    +
  • Ergebnis -1: Wert "a" ist kleiner als Wert "b"
  • +
  • Ergebnis 1: Wert "a" ist größer als Wert "b"
  • +
  • Ergebnis 0: Wert "a" und "b" sind gleich, Positionen behalten
  • +
+
+
\ No newline at end of file diff --git a/src/components/slides/javascript/02-complex-datatypes/index.astro b/src/components/slides/javascript/02-complex-datatypes/index.astro new file mode 100644 index 0000000..e026b7f --- /dev/null +++ b/src/components/slides/javascript/02-complex-datatypes/index.astro @@ -0,0 +1,11 @@ +--- +import Title from './title.astro'; +import Objects from './objects.astro'; +import Arrays from './arrays.astro'; +--- + +
+ + <Objects /> + <Arrays /> +</div> \ No newline at end of file diff --git a/src/components/slides/javascript/02-complex-datatypes/objects.astro b/src/components/slides/javascript/02-complex-datatypes/objects.astro new file mode 100644 index 0000000..a2c6796 --- /dev/null +++ b/src/components/slides/javascript/02-complex-datatypes/objects.astro @@ -0,0 +1,248 @@ +<section> + <section> + <h2>Objekte in JavaScript</h2> + </section> + + <section> + <p>Objekte in JS sind eine der wichtigstens Grundpfeiler, die die Sprache so mächtig machen.</p> + <p>In JavaScript ist das Objekt das alles Abbildet (in Fakt, alles in JavaScript ist ein Objekt, auch die anderen Datentypen).</p> + </section> + + <section> + <h3>Definition eines Objektes</h3> + </section> + + <section> + <p>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.</p> + <p>Objekte kommen am einem Key-Value-Speicher an nahesten. Ein Key kann dabei ein beliebiger string sein, der Wert kann alles annehmen.</p> + <p>Ein Objekt wird einfach mit Geschweiften (Curly) Klammern definiert.</p> + </section> + + <section> + <pre class="js"><code data-trim data-line-numbers is:raw> + const meinObjekt = { + key: "value", + numeric: 5, + boolean: false, + } + </code></pre> + </section> + + <section> + <p>Objekte können auch ineinander geschachtelt werden (in beliebiger Tiefe)</p> + <pre class="js"><code data-trim data-line-numbers is:raw> + const geschachtelt = { + level1: { + level2: { + level3: { + level4: "Und so weiter...", + }, + }, + }, + }; + </code></pre> + </section> + + <section> + <p>Auch wenn JS diese Flexibilität bietet, sollte die Datenstruktur möglichst flach gehalten werden.</p> + <p>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.</p> + </section> + + <section> + <p>Zugriffe auf Inhalte in einem Objekt können über 2 Wege erreicht werden</p> + <pre class="js"><code data-trim data-line-numbers is:raw> + const obj = { + value: 5, + nested: { + value: 42, + }, + }; + + // Dot-Notation + console.log(obj.nested.value); + + // Array-Like-Access + console.log(obj['nested']['value']); + </code></pre> + </section> + + <section> + <p>Gängig ist die Verwendung der dot-notation, hier ist aber das Wissen der keys zur Entwicklungszeit notwendig.</p> + <p>Wenn programmatisch auf die Inhalte Zugegriffen werden soll, kann dies nur über die Array-Notation geschehen.</p> + <p>Zusätzlich ist die Array-Notation notwendig, wenn Zeichen verwendet werden, die bereits eine andere Verwendung haben (Beispiel "-", " ")</p> + </section> + + <section> + <pre class="js"><code data-trim data-line-numbers is:raw> + 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]); + </code></pre> + </section> + + <section> + <p>Inhalte in Objekten können auch beliebig geändert werden</p> + <pre class="js"><code data-trim data-line-numbers is:raw> + const obj = { + value: 5, + }; + + obj.value = 42; + + console.log(obj.value); + </code></pre> + </section> + + <section> + <p>Unstimmigkeit gefunden?</p> + <p><code>obj</code> wurde mit const initialisiert, dessen Inhalt kann aber manipuliert werden.</p> + <p>Mein Fehler? Nein. Das ist JavaScript und seine Komplexen Datentypen funktionieren so.</p> + </section> + + <section> + <p>Wir müssen nun erstmal verstehen was der Unterschied zwischen simplen und komplexen Datentypen ist, und was das für Folgen hat.</p> + <p>JavaScript speichert simple Datentypen wie Zahlen oder Strings in Stack ähnlichen Speicher.</p> + <p>Komplexe Objekte werden im Heap allokiert.</p> + <p>Das alles ist eine vereinfachte Darstellung. Die internen Vorgänge sind viel komplexer und für den Alltag eines Web-Developers auch nicht notwendig.</p> + </section> + + <section> + <p>Kurzer Recap: Heap vs Stack</p> + <p>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.</p> + <p>Der Heap stellt einen größeren Speicherbereich da, in dem Inhalte dynamisch abgelegt werden können.</p> + <p>Im Heap können dynamische / komplexe Datenstrukturen mittels einer Speicherreferenz verwendet werden.</p> + </section> + + <section> + <p>Was steht "im Hintergrund" nun in der Variable, wenn ein Objekt initialisiert wird?</p> + <p>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.</p> + <p>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.</p> + </section> + + <section> + <p>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.</p> + <p>Ändern wir nun eine Eigenschaft im Objekt (Property), ändern wir den Wert im <strong>Heap</strong>. Die Adresse im Stack bleibt gleich.</p> + <p>Und hier liegt der Punkt: Der Wert im Stack wird nicht modifiziert, entsprechend bleibt der Wert "konstant" und stellt keine Verletzung der <code>const</code> Bedingung aus.</p> + </section> + + <section> + <p>Weitere Besonderheiten mit der Speicherbelegung von Objekten</p> + </section> + + <section> + <p>Wenn ein Objekt aus einem anderen Objekt generiert wird, erfolgt <strong>kein</strong> Deep-Copy.</p> + <p>In der Realität geschieht ein <strong>copy-by-reference</strong>.</p> + <pre class="js"><code data-trim data-line-numbers is:raw> + const obj = {}; + const otherObj = obj; + + // true + console.log(obj === otherObj); + </code></pre> + </section> + + <section> + <p>Nun ist wichtig zu beobachten, was passiert wenn wir das Objekt an einer beliegen Variable ändern:</p> + <pre class="js"><code data-trim data-line-numbers is:raw> + const obj = {}; + const otherObj = obj; + + obj.value = 42; + + // 42 + console.log(otherObj.value); + </code></pre> + </section> + + <section> + <p>Durch diese beiden Beispiele wird nochmals eindeutig, dass wir bei der Handhabung von Objekten genau darauf achten müssen, was wir machen.</p> + <p>Moderne Frameworks verwenden diese Konzepte für die eigene Datenhaltung. Hier kann es bei nichtbeachtung der "Regeln" zu ungewollten Problemen kommen.</p> + </section> + + <section> + <h3>Object-Spezifische Funktionen</h3> + </section> + + <section> + <p>Sollte es notwendig sein ein Objekt "read-only" zu machen, nutzen Sie <code>Object.freeze(objectToFreeze)</code></p> + <pre class="js"><code data-trim data-line-numbers is:raw> + const myObject = { value: 5 }; + Object.freeze(myObject); + + // Erzeugt einen Error + myObject.value = 42; + </code></pre> + <p>Obwohl es Sinnvoll sein kann, wird <code>Object.freeze()</code> recht selten eingesetzt.</p> + </section> + + <section> + <p>Objekte können auch ohne Probleme erweitert werden:</p> + <pre class="js"><code data-trim data-line-numbers is:raw> + const obj = { + value: 5, + }; + + // Neue Property mit Namen "type" + obj.type = "number"; + </code></pre> + </section> + + <section> + <p>Sobald eine Property definiert ist, existiert sie im Objekt, auch wenn diese auf <code>undefined</code> gesetzt wird.</p> + <pre class="js"><code data-trim data-line-numbers is:raw> + const obj = { value: 5, type: "number" }; + obj.type = undefined; + + console.log(obj); + // Object { value: 5, type: undefined }; + </code></pre> + </section> + + <section> + <p>Soll eine Property wirklich entfernt werden, kann man dies mit dem <code>delete</code> keyword bewerkstelligen.</p> + <pre class="js"><code data-trim data-line-numbers is:raw> + const obj = { value: 5, type: "number" }; + delete obj.type + + console.log(obj); + // Object { value: 5 }; + </code></pre> + </section> + + <section> + <p>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.</p> + <pre class="js"><code data-trim data-line-numbers is:raw> + const obj = { value: 5 }; + + // ['value'] + console.log(Object.keys(obj)); + + // [5] + console.log(Object.values(obj)); + + // [['value', 5]]; + console.log(Object.entries(obj)); + </code></pre> + </section> + + <section> + <p>Um zu prüfen, ob ein Objekt ein Property hat, nutzt man die Funktion <code>Object.hasOwn</code></p> + <pre class="js"><code data-trim data-line-numbers is:raw> + const obj = { value: 5 }; + + // true + console.log(Object.hasOwn(obj, 'value')); + // false + console.log(Object.hasOwn(obj, 'other')); + </code></pre> + </section> + +</section> \ No newline at end of file diff --git a/src/components/slides/javascript/02-complex-datatypes/title.astro b/src/components/slides/javascript/02-complex-datatypes/title.astro new file mode 100644 index 0000000..4748e45 --- /dev/null +++ b/src/components/slides/javascript/02-complex-datatypes/title.astro @@ -0,0 +1,3 @@ +<section> + <h1>Komplexe Datentypen <br>(Objekte und Arrays)</h1> +</section> \ No newline at end of file diff --git a/src/pages/slides/javascript/02-complex-datatypes.astro b/src/pages/slides/javascript/02-complex-datatypes.astro new file mode 100644 index 0000000..af1c719 --- /dev/null +++ b/src/pages/slides/javascript/02-complex-datatypes.astro @@ -0,0 +1,8 @@ +--- +import Reveal from '../../../layouts/Reveal.astro'; +import Slides from '../../../components/slides/javascript/02-complex-datatypes/index.astro'; +--- + +<Reveal title="JavaScript - Komplexe Datentypen"> + <Slides /> +</Reveal>