10 Essentials (nicht nur) für JavaScript-Einsteiger

06.08.2024
Von 
Matthew Tyson ist Java-Entwickler und schreibt unter anderem für unsere US-Schwesterpublikation Infoworld.com.
Diese Tipps und Code-Beispiele für JavaScript verhindern, von den immergleichen Unwägbarkeiten geplagt zu werden.
Dieser Artikel hilft, wenn die JavaScript-Wut die Oberhand gewinnt.
Dieser Artikel hilft, wenn die JavaScript-Wut die Oberhand gewinnt.
Foto: Roman Samborskyi | shutterstock.com

JavaScript ärgert nicht nur Dev-Neulinge - auch erfahrenere Entwickler haben oft in mehrfacher Hinsicht mit der Programmiersprache zu kämpfen. In diesem Artikel betrachten wir die zehn gängigsten Probleme in diesem Zusammenhang - und wie Ihnen diese künftig erspart bleiben.

1. Arrays händeln

Mit Arrays zu arbeiten ist eine Sache, um die JavaScript-Entwickler nicht herumkommen. Die Daten innerhalb dieser Arrays können Objekte, Zahlen oder Strings sein, die geordnet, organisiert oder in kleinere Teile zerlegt werden müssen.

Um Arrays zu händeln, stehen Ihnen viele Möglichkeiten offen - unter anderem auch klassische, imperative Loops. Den einen richtigen Weg gibt es dabei nicht. Allerdings stellt (modernes) JavaScript eine Reihe praktischer funktionaler Operationen zur Verfügung. Sie müssen lediglich wissen, welche zu welcher Zeit anzuwenden ist. Betrachten wir beispielsweise folgendes Array:

const products = [

{ id: 1, name: "Apple", price: 1.99, inStock: true },

{ id: 2, name: "Banana", price: 0.79, inStock: false },

{ id: 3, name: "Orange", price: 2.49, inStock: true },

];

Wollten wir in diesem Szenario ausschließlich nach Produkten filtern, die auf Lager sind und diese nach aufsteigendem Preis sortieren, würde das wie folgt funktionieren:

const availableProducts = products.filter(product => product.inStock)

.sort((a, b) => a.price - b.price);

Nun enthält availableProducts nur noch die Objekte, auf die das Attribut inStock zutrifft und die Liste wird entsprechend sortiert. Die Methoden filter und sort sind hier bereits integriert und nehmen Funktionen als Argumente an. Hierbei handelt es sich um "Higher-Order Functions" - ein grundlegendes Element der funktionalen Programmierung.

Jedes Funktionsargument nimmt das/die Element(e) auf, die bearbeitet werden sollen. Im Fall von filter wird das Element im resultierenden Array behalten, wenn die Funktion true zurückgibt. Mit Blick auf sort() werden zwei Argumente übergeben, während der Algorithmus das Array durchläuft. Fällt das Resultat negativ aus, wird das erste Element zuerst sortiert und umgekehrt. Wenn 0 zurückgegeben wird, sind die Elemente identisch.

2. DOM anpassen

Um mit dem Document Object Model (DOM) zu arbeiten (das die Benutzeroberfläche darstellt und Änderungen ermöglicht), kommen häufig Reactive Frameworks zum Einsatz. Trotzdem müssen JavaScript-Entwickler immer noch direkt mit dem DOM interagieren. Dabei geht es im Wesentlichen um zwei Dinge:

  • auf Events zu reagieren und

  • Elemente und Properties anzupassen.

Ein Beispiel:

<!DOCTYPE html>

<html>

<body>

<h1 id="heading">Welcome to our website!</h1>

<button id="change-button">Change Heading</button>

<script>

const changeButton = document.getElementById("change-button");

changeButton.addEventListener("click", function(event) {

const clickedElement = event.target;

clickedElement.style.color = "red";

const heading = document.getElementById("heading");

heading.textContent = "This heading has been changed!";

});

</script>

</body>

</html>

Hierbei handelt es sich um eine simple HTML-Seite mit einem Titel (h1) und einer Schaltfläche (button). Dabei wird ein DOM-Tree erstellt, in dem die Elemente <h1> und <button> innerhalb von <body> angesiedelt sind. Darüber hinaus führt das <script>-Tag, JavaScript aus. Das Button-Element "holt" sich JavaScript über die ID, respektive die Funktion document.getElementById("change-button").

Auf der Schaltfläche wird mit addEventListener ein Ereignis-Listener gesetzt. Das ist der grundlegende Mechanismus, um Webseiten "reactive" zu gestalten. Allerdings gibt es viele verschiedene Typen von Events - in unserem Fall wollen wir mit "click" auf den Klick auf die Schaltfläche reagieren. Mit dem zweiten Argument können wir eine Callback-Funktion bereitstellen.

Die Callback-Funktion erhält ein einziges Argument, das wir event nennen. Es weist mehrere Eigenschaften auf die Sie verwenden können, die wichtigste ist target. Diese Property enthält das Element, auf das geklickt wurde. Wir verwenden es, um die Farbe der Schaltfläche in Rot zu ändern.

Abschließend ziehen wir das h1-Überschriftenelement per ID heran und verändern seinen Text. Die Text- und Farbveränderungen sind Beispiele für die Verwendung von DOM-Elementattributen.

3. Asynchron programmieren

Modernes JavaScript und Asynchronous Programming gehen gut zusammen. Dafür gibt es drei wesentliche Mechanismen:

  • Callbacks,

  • Promises und

  • async/await.

Callbacks funktionieren traditionell:

let myCallback = function(){

console.log("I was called after one second.");

}

setTimeout(myCallback, 1000);

Auf diese Weise können wir die myCallback-Funktion asynchron ausführen - in diesem Fall nach 1.000 Millisekunden. Dasselbe könnten wir auch mit einem Promise erledigen:

function waitOneSecond() {

return new Promise((resolve, reject) => {

setTimeout(() => {

resolve("I was called after one second.");

}, 1000);

});

}

waitOneSecond()

.then(message => console.log(message))

.catch(error => console.error(error));

Hierbei handelt es sich immer noch um einen asynchronen Prozess, genauer gesagt einen Asynchronous Callback, der in einem Promise verpackt ist. Auf diese Weise können Sie die then- und catch-Methoden callen, um die Ergebnisse ohne verschachtelte Callbacks zu verarbeiten.

4. Fehler behandeln

Code kann jederzeit Ausnahmen respektive Fehler aufwerfen, die ein Problem indizieren:

throw new Error("Something is not right here.")

Das stoppt den Execution-Flow und ruft den Call Stack auf den Plan. Wenn dieser try/catch-Blöcke enthält, wird der erste gefundene den Fehler behandeln. Hier ein kompaktes Beispiel:

try{

throw new Error("Something is not right here.")

} catch(e) {

console.log("Got an error: " + e);

}

Das führt zu folgendem Print-Output:

Got an error: Error: Something is not right here.

Darüber hinaus ist auch komplexeres Error Handling möglich, beispielsweise in Form von Recover-, Retry- und anderen Strategien. Sie können auch einen finally-Block definieren, der aufgerufen wird, wenn ein Fehler aufgetreten ist (oder nicht):

try{

throw new Error("Something is not right here.")

} catch(e) {

console.log("Got an error: " + e);

} finally {

console.log("No matter what, I'll print.");

}

Auch wenn es um asynchrone Operationen mit Promises geht, können catch() und finally() auf ähnliche Weise eingesetzt werden:

function waitOneSecond() {

return new Promise((resolve, reject) => {

setTimeout(() => {

reject(new Error("Network error!"));

}, 1000);

});

}

waitOneSecond()

.then(message => console.log(message))

.catch(error => console.error("Error:", error.message)) .finally(() => console.log("This always executes, regardless of errors."));

In diesem Fall werden die catch()- und finally()-Blöcke immer ausgeführt, weil stets ein Fehler auftritt. Wenn die normale Execution keinen Fehler auslöst, erfolgt auch der catch-Call nicht.

5. In Objekte einsteigen

Objekte sind ein zentraler Bestandteil der Programmierarbeit mit JavaScript. Mit JSON verfügt JavaScript auch über eine integrierte Notation, um diese zu beschreiben:

let campingSpot = {

name: "Willow Creek",

location: "Big Sur"

}

Auf die Eigenschaften des Objekts greifen Sie folgendermaßen zu:

console.log("We're going camping at " + campingSpot.name);

Objekte in JavaScript sind nicht auf JSON beschränkt - Behavior lässt sich auch in Form von Funktionen definieren:

let campingSpot = {

name: "Willow Creek",

describeWater: function(){

console.log("Very cold");

}

}

Dabei sind Sie auch nicht auf einzelne Objekte beschränkt und können auch Objektklassen definieren:

class CampingSpot {

constructor(name, location) {

this.name = name;

this.location = location;

}

describeWater() {

console.log("The water at " + this.name + " is very cold.");

}

}

Jetzt können wir nach Belieben Instanzen des CampingSpot-Objekts erstellen:

let willowCreek = new CampingSpot("Willow Creek", "Big Sur");

let sunsetStateBeach = new CampingSpot("Sunset State Beach", "Santa Cruz");

6. Remote APIs nutzen

JavaScript-Programme brauchen regelmäßig Zugriff auf (Service) APIs, die Daten und Funktionalitäten bereitstellen. Dabei suchen die meisten Entwickler nach Lösungen, um diese Daten von Remote-Schnittstellen abzugreifen, die Antworten zu parsen und diese in ihre Applikationen zu integrieren.

Glücklicherweise enthält JavaScript sowohl in Client- als auch in Serverumgebungen die Fetch API. Sie bietet eine simple und direkte Möglichkeit für HTTP-Calls. In folgendem Beispiel rufen wie eine Liste von Stars-Wars-Filmen über den SWAPI-Service ab:

async function getStarWarsFilms() {

try {

const response = await fetch('https://swapi.dev/api/films');

if (!response.ok) {

throw new Error(`Error fetching Star Wars films: ${response.status}`);

}

const data = await response.json();

console.log(data.results);

} catch (error) {

console.error("Error:", error);

}

}

getStarWarsFilms();

Weil es sich hierbei um einen GET-Request handelt, können Sie einfach fetch('https://swapi.dev/api/films') verwenden. Die Nutzung von await sorgt dabei dafür, dass wir eine Pause einlegen können, während der Request rausgeht und die Antwort zurückkommt. Um festzustellen, ob die Anfrage erfolgreich war, nutzen wir das response-Objekt in Form von response.ok.

7. Strings modifizieren

Strings sind ein grundlegendes Element, das in allen möglichen Situationen zum Einsatz kommt. Werfen wir einen Blick auf ein String-Beispiel:

const taoTeChingVerse1 =

`The Tao that can be told is not the eternal Tao.

The name that can be named is not the eternal name.

The nameless is the beginning of heaven and earth.

The named is the mother of all things,`;

Nehmen wir an, wir wollten nur die erste Zeile der ersten Strophe:

const firstLine = taoTeChingVerse1.slice(0, 48);

Übersetzt bedeutet das: Gib den Substring zwischen dem ersten und dem 48. Zeichen aus. Um zu ermitteln, wo das Wort "Tao" erstmals vorkommt, gehen Sie wie folgt vor:

taoTeChingVerse1.indexOf("Tao"); // returns 4

Wenn Sie nun Wörter ersetzen möchten, greifen Sie auf simples Regex zurück. In unserem Beispiel ersetzen wir jedes "told" durch "spoken":

const newText = text.replace(/told/g, "spoken");

Die Slashes markieren einen regulären Ausdruck, der auf "told" gematcht wird. Das Suffix g steht dabei für "global", erfasst also jedes "told". Das zweite Argument von replace() ist das Token, das ausgetauscht werden soll.

Wenn Sie zwei Strings zusammenfügen wollen, genügt dafür ein einfacher Plus-Operator:

let fullVerse = taoTeChingVerse1 + "Having both but not using them, Think of them as the constant.");

Die Länge der Zeichenkette können Sie dabei jederzeit wie folgt zählen:

fullVerse.length; // return 261

8. JSON-Objekte konvertieren

Ein weiteres häufiges Erfordernis bei der Arbeit mit JavaScript: JSON-Objekte zu einem String konvertieren - oder umgekehrt. Das funktioniert folgendermaßen:

let website = {

name: "InfoWorld",

url: "www.infoworld.com"

}

let myString = JSON.stringify(website);

Um den String in Objekt umzuwandeln, genügt:

JSON.parse(myString);

9. Datumsoperationen durchführen

Mit dem in JavaScript integrierten Date-Objekt können, respektive müssen Entwickler sich regelmäßig auseinandersetzen. Für den Anfang können Sie das heutige Datum wie folgt ermitteln:

const today = new Date();

Die einzelnen Bestandteile ermitteln Sie so:

console.log(today.getFullYear()); // Get the year (e.g., 2024)

console.log(today.getMonth()); // Get the month (0-indexed, e.g., 4 for May)

console.log(today.getDate()); // Get the day of the month (e.g., 21)

console.log(today.getHours()); // Get hours (e.g., 13 for 1 PM)

console.log(today.getMinutes()); // Get minutes (e.g., 27)

console.log(today.getSeconds()); // Get seconds (e.g., 46)

Und folgender Befehl befördert Sie sieben Tage in die Zukunft:

date.setDate(date.getDate() + 7);

10. Mit Zahlen arbeiten

JavaScript ist inzwischen bereits standardmäßig ziemlich gut darin, mit Zahlen umzugehen. Für mehr mathematische Performance steht zudem die integrierte Math-Bibliothek bereit.

Um Zahlen zu erstellen, gehen Sie folgendermaßen vor:

let age = 30;

let pi = 3.14159;

let billion = 1000000000;

Sie können diese aber auch aus einem String konvertieren:

let convertedNumber = Number("42");

Normale Operationen sind dabei relativ selbsterklärend:

let addition = pi + 3; // addition now equals 6.14159

Darüber hinaus können Sie Zahlen auch schnell runden mit:

Math.ceil(pi); // round to nearest upper integer (4)

Math.floor(pi); // round to lowest int (3)

Oder die größte Zahl ermitteln mit:

Math.max(100, 5, 10, 73); // returns 100

Wenn Sie mit einem Array starten, können Sie auch den Spread-Operator nutzen:

let numbers = [100, 5, 10, 73];

Math.max(...numbers); // returns 100

Abschließend noch der Hinweis, wie Sie die "Evenness" überprüfen:

let isEven = 10 % 2 === 0; // true (checks if remainder is 0)

(fm)