JavaScript/Variable
Eine Variable lässt sich am besten mit einem Behälter, der genau einen Wert aufnehmen kann, vergleichen. Der Behälter ist ein von JavaScript verwalteter Speicherplatz mit einem (unveränderlichen) Namen. In einem solchen Speicherplatz können Sie beliebige Werte ablegen und später wieder verwenden. Sie können einen vorhandenen Wert auch beliebig oft durch andere Werte ersetzen. Die Möglichkeit, Werte zu errechnen, in Variablen zu speichern und weiterzugeben, gibt Programmen ihre Flexibilität.
Bei einem solchen Wert kann es sich beispielsweise um eine Zahl handeln. JavaScript kennt unterschiedliche Wertetypen, auch solche, die sich aus anderen Werten zusammensetzen. Im nächsten Artikel dieser Reihe werden wir das genauer betrachten. An dieser Stelle soll nur erwähnt werden, dass eine Variable jeden der in JavaScript verfügbaren Werte speichern kann und - im Gegensatz zu vielen anderen Sprachen - nicht auf einen bestimmten Wertetyp festgelegt werden muss.
Um eine Variable zu erzeugen, muss sie für JavaScript bekannt gemacht („deklariert“) werden. Mit der Deklaration wird der erforderliche Speicherplatz bereitgestellt und ihm ein Name zugeordnet. Darüber hinaus legt der Ort, an dem sich die Deklaration befindet, den Gültigkeitsbereich der Variablen fest, also den Bereich Ihres Programms, in dem diese Variable sichtbar und verwendbar ist.
wiki
und Wiki
handelt es sich um unterschiedliche Variablen!Um den Wert, der in einer Variablen gespeichert ist, wieder auszulesen, schreiben Sie den Variablennamen einfach dorthin, wo Sie andernfalls den Wert hingeschrieben hätten.
kante = 5;
fläche = kante * kante;
Für dieses Beispiel wurden die Variablen kante
und fläche
noch nicht deklariert. Wie das geht, zeigen wir gleich. Nehmen Sie einstweilen an, das sei irgendwie geschehen.
In der ersten Zeile wird in der Variablen kante
die Zahl 5 gespeichert. Diese Zeile bildet eine so genannte Wertzuweisung, die durch den Zuweisungsoperator =
ausgelöst wird. In der zweiten Zeile wird die Variable kante
in einer Formel verwendet, um den Wert zu ermitteln, der in der Variablen fläche
gespeichert werden soll. Der Rechenoperator *
bewirkt eine Multiplikation, der Wert wird als 25 lauten.
Inhaltsverzeichnis
Deklaration von Variablen
JavaScript unterscheidet vier Arten, Variablen zu deklarieren. Drei davon erfolgen mit den Schlüsselwörtern var
, let
und const
, die vierte besteht darin, Parameter einer Funktion zu deklarieren (die sich aber so verhalten, als seien sie mit var
deklariert). Parameter werden wir zusammen mit Funktionen betrachten.
var
var
ist veraltet und sollte in Zukunft nicht mehr verwendet werden. Stattdessen wird empfohlen, Variablen mit dem Schlüsselwort let
zu deklarieren. Browser unterstützen weiterhin var
aus Kompatibilitätsgründen.Als JavaScript entstand, gab es nur das Schlüsselwort var
, um eine Variable zu deklarieren. Notieren Sie einfach var
und listen Sie danach die Variablennamen auf, die Sie verwenden möchten. Wenn Sie mehrere Variablen auf einmal deklarieren wollen, trennen Sie ihre Namen durch ein Komma.
var kante;
var fläche, volumen;
Für die so erzeugten Variablen ist zunächst kein Wert bekannt. Da es aber ungeschickt wäre, in dem bereitgestellten Speicherplatz irgendwelche alten Daten vorzufinden, schreibt JavaScript in neue Variablen automatisch den speziellen Wert undefined
hinein - das ist ein JavaScript-Schlüsselwort, das den Wert für leere Variablen repräsentiert.
Außer mit dem Operator zur Wertzuweisung können Sie einer Variable auch sofort bei ihrer Deklaration einen Wert geben. Das nennt man Initialisierung.
Führen wir unsere beiden Beispiele nun zusammen. Wir zeigen die Deklaration einmal ohne und einmal mit Initialisierung.
var kante; // Deklariert die Variable kante, ohne sie zu initialisieren
kante = 5; // Speichern der Zahl 5 in kante
var fläche = kante * kante; // Deklariere die Variable fläche und initialisiere sie
// sofort mit dem Ergebnis einer Berechnung
Hebung
Bevor JavaScript ein Programm ausführt, liest es es komplett ein und übersetzt es in einen internen Zwischencode. Bei diesem Schritt registriert es auch sämtliche Deklarationsanweisungen. Variablennamen sind damit automatisch ab dem Beginn des Programmbereichs bekannt, in dem sie deklariert wurden.
Das Besondere an var
-Deklarationen ist, dass sie auch sofort zum Beginn dieses Programmbereichs gültig sind. Dieses Konzept heißt Hebung (engl. hoisting). Sie können einer solchen Variablen deshalb bereits einen Wert zuweisen, bevor die Programmzeile mit der var
-Deklaration erreicht wurde. Aber Vorsicht, das gilt nur für die Deklaration. Wenn Sie in der Deklaration eine Initialisierung vorgesehen haben, findet sie erst an der Stelle statt, wo die var
-Anweisung steht. Bis dahin ist die Variable uninitialisiert.
var x = y; // y ist hier bereits deklariert, aber noch undefined
var y = 7; // y wird deklariert und mit 7 initialisiert
Wegen der Hebung aller var
-Deklarationen bricht das Programm in Zeile 1 nicht mit der Fehlermeldung ab, dass y undeklariert sei. Aber weil y erst in Zeile 1 initialisiert wird, bekommt x den Wert undefined
.
const und let
Die var
Anweisung hat zum einen die merkwürdige Eigenschaft des Hebung an den Beginn des Gültigkeitsbereichs, und zum anderen hat sie gewisse Einschränkungen bezüglich der möglichen Gültigkeitsbereiche, auf die wir später eingehen.
In der JavaScript-Sprachversion ECMAScript 2015 (ES6) wurden deshalb die Anweisungen const
und let
zur Variablendeklaration hinzugefügt. Das Verhalten dieser Anweisungen entspricht eher dem von Sprachen wie Java oder C. Das heißt: die grundsätzliche Funktionalität ist wie bei var
, aber die Hebung entfällt. Damit werden Sie beim Programmieren dazu angehalten, Variablen immer erst zu deklarieren, bevor Sie sie verwenden. Die Programmlesbarkeit verbessert sich dadurch deutlich. Die fehlende Hebung ermöglicht es auch, Variablen nur für einen Teilbereich einer Funktion zu deklarieren.
const
und let
statt var
und beachten Sie die Empfehlungen für die Praxis.Die neuen Deklarationsanweisungen unterscheiden zwischen veränderbaren und unveränderbaren Variablen. Unveränderbare Variable - das klingt wie ein Widerspruch. Solche Variablen sind aber nicht nutzlos. Man benötigt oft Speicherplätze, um ein Zwischenergebnis zu speichern oder um einen Verweis auf ein HTML-Element festhalten zu können, das man im Folgenden manipulieren möchte. Wenn man Werte, die man nicht mehr ändert, als konstant deklariert, hat JavaScript auch bessere Möglichkeiten, die Programmausführung zu optimieren.
Es ist auch eine häufige Fehlerquelle beim Programmieren, dass man den Wert einer Variablen ändert, diese Änderung aber an einer anderen Stelle im Programm nicht berücksichtigt. Es gibt Programmiersprachen, die veränderbare Variablen gar nicht kennen, allerdings programmiert man darin auch deutlich anders als mit JavaScript.
- const
- erzeugt eine unveränderbare (immutable) Variable, auch symbolische Konstante genannt. Sie müssen eine solche Konstante beim Deklarieren initialisieren. Damit wird der Variablenname an einen festen Wert gebunden und behält ihn, bis die Variable ihre Gültigkeit verliert. (Hauptartikel)
- let
- erzeugt eine änderbare Variable, analog zu
var
. Sie können sie sofort initialisieren, oder den Wert aufundefined
belassen und später einen Wert zuweisen. (Hauptartikel)
const button = document.querySelector("#interaktiv"),
output = document.querySelector("output"),
PI = 3.14159265359;
let text = "Hallo Welt!";
let alter;
Bei document.querySelector(...)
handelt es sich um einen Zugriff auf die Programmierschnittstelle des Browsers - das DOM. Damit erhalten Sie spezielle Werte, sogenannte Objekte, mit denen Sie HTML Elemente des dargestellten Dokuments abfragen und manipulieren können.
Solche Objekte ändern sich höchstens inhaltlich, das Objekt selbst bleibt aber gültig, solange Sie es nicht ausdrücklich aus dem DOM löschen. Deswegen ist es sinnvoll, diese Objekte in einer mit const
deklarierten Variablen zu speichern.
Einen „wohlbekannten“ Wert wie PI, der in Kreisberechnungen verwendet wird, kann man ebenfalls als Konstante ablegen, das ist praktischer, als ständig viele Nachkommastellen zu tippen. Es sei aber auch nicht verschwiegen, dass es ein eingebautes JavaScript Objekt Math gibt, das Ihnen π fertig bereitstellt.
Darüber hinaus deklariert das Beispiel - nur zur Demonstration - zwei veränderbare Variablen text
und alter
. text
wird sofort mit einer Zeichenkette initialisiert.
Es gibt Diskussionen darüber, ob man Konstanten in Großbuchstaben schreiben sollte. Dies wird in vielen Programmierumgebungen bei vordefinierten Konstanten so gemacht, und es ist nicht falsch, wenn Sie das auch so halten. Bei den als const deklarierten Variablen button
und output
aus dem vorigen Beispiel ist das aber etwas anderes. Diese enthalten berechnete Werte, die für den jeweiligen Programmlauf gültig sind, und keine immer gleichen, wohlbekannten Werte[1].
Datentypen
- Hauptartikel: Datentypen in JavaScript
Wie eingangs erwähnt, verfügt JavaScript über unterschiedliche Typen von Werten. Es gibt den speziellen Wert undefined
, es gibt Zahlen, Zeichenketten, Wahrheitswerte, die schon erwähnten Objekte und die sogenannten Arrays. Objekte können Sie sich wie einen Karteikasten vorstellen, in dem Sie Werte unter einem Schlüsselbegriff ablegen können. Bei diesen Werten kann es sich wieder um beliebige JavaScript-Werte handeln. Arrays sind ebenfalls Objekte, aber ermöglichen außer Schlüsselbegriffen noch zusätzlich die Verwendung von Indexnummern.
Variablen in JavaScript müssen nicht darauf festgelegt werden, für welchen Wertetyp sie gedacht sind. Wenn Sie Java oder C++ kennen, kommt Ihnen das vermutlich ungewohnt vor, aber in JavaScript ist es so, dass jeder Wert, mit dem Sie umgehen, auch die Information enthält, welchen Datentyp er hat. Ob eine bestimmte Operation auf einen Wert anwendbar ist, wird erst geprüft, wenn das Programm ausgeführt wird.
Einige Operatoren von JavaScript verfügen auch über die Fähigkeit, sich an den Typ der Werte anzupassen, auf die man sie anwendet. So bewirkt der Operator +
beispielsweise eine Addition, wenn man ihn auf Zahlen anwendet. Benutzt man ihn für Zeichenketten, werden die beiden Ketten aneinander gehängt. Der Multiplikationsoperator *
hingegen versucht, Zeichenketten als Zahl zu deuten, wenn man ihn auf sie anwendet.
Diese Flexibilität bedeutet auch, dass Sie einer Variablen erst eine Zahl, dann ein Objekt, danach einen Text und zum Schluss sogar wieder undefined
zuweisen können, sie macht das alles mit. Ob Sie als Programmierer danach noch wissen, was Sie mit einer solchen Variablen anfangen können, ist eine andere Frage.
// Berechnung Diagonale A4-Papier
let breite = 210;
let höhe = 297;
let diagonale = Math.hypot(breite, höhe);
let ausgabe = "Die Diagonale eines A4-Blattes ist " + Math.round(diagonale) + " mm lang.";
console.log(ausgabe);
Die Werte für breite
, höhe
und diagonale
sind Zahlen. Die Berechnung der Diagonalen verwendet die eingebaute JavaScript-Funktion Math.hypot, die genau für diesen Zweck gemacht ist (hypot steht für Hypotenuse, die Diagonale des A4-Blattes entspricht der Hypotenuse eines rechtwinkligen Dreiecks, dessen Katheten aus den Blattkanten bestehen).
Für die Ausgabe wird eine weitere eingebaute Funktion verwendet: Math.round. Sie rundet einen Wert, der Nachkommastellen besitzt, auf die nächste ganze Zahl.
Die Initialisierung von ausgabe
zeigt, wie JavaScript eine Zahl, die an der Verkettung von Zeichenketten beteiligt ist, automatisch in eine Zeichenkette umwandelt und mit verkettet. In vielen anderen Programmiersprachen hätte dies eine Fehlermeldung des Sprachübersetzers oder einen Programmabbruch zur Folge. Allerdings hat sich dieses Verfahren auch als unübersichtlich erwiesen. Seit der Sprachversion „ECMAScript 2015“ verfügt JavaScript über sogenannte Template-Literale, die das Einsetzen von Werten in Zeichenketten verbessern.
Gültigkeitsbereiche
Wir haben Variablen bisher unabhängig von dem Umfeld betrachtet, in dem sie verwendet werden. Das liegt vor allem daran, dass dieser Artikel ganz am Anfang der JavaScript-Artikelreihe steht und viele Konzepte, die zum Verständnis von Gültigkeitsbereichen erforderlich sind, noch gar nicht bekannt sind. Deshalb kann es an dieser Stelle nur einen kurzen Überblick geben.
Grundsätzlich kennt JavaScript vier Arten von Gültigkeitsbereichen oder Scopes. Diese Gültigkeitsbereiche werden ausschließlich auf Basis des JavaScript-Programmtextes gebildet, den Sie verfassen. Sie hängen nicht davon ab, wie Sie Ihre erstellten Programmbausteine zur Ablaufzeit miteinander kommunizieren lassen.
- Global Scope
- Solange Sie keine Funktionen schreiben oder Anweisungsblöcke bilden, befinden Sie sich im Global Scope. Variablen, die darin deklariert werden, sind überall im Programm sichtbar. Den Global Scope gibt es naturgemäß nur einmal.
- Module Scope
- Dies ist ein Sonderfall des Global Scope für Module nach dem ECMAScript 2015 Standard. Deklarationen auf oberster Ebene, die in einem solchen Modul stattfinden, sind nur innerhalb dieses Modules sichtbar. Jedes Modul hat seinen eigenen Module Scope.
- Function Scope
- Funktionen sind ein Sprachmittel, um wiederverwendbaren Programmteile zu erzeugen. Dazu gehört auch, dass diese Programmteile über eigene Variablen verfügen, die bei jeder Verwendung der Funktion neu bereitgestellt werden. Variablen, die Sie in einer Funktion deklarieren, sind deshalb nur innerhalb dieser Funktion sichtbar.
- Es ist möglich, innerhalb einer Funktion weitere Funktionen zu erstellen. Die Variablen der äußeren Funktion sind auch in den inneren Funktionen sichtbar und verwendbar.
- Einer Funktion wird jedesmal, wenn sie aufgerufen wird, für ihren eigenen Function Scope Speicherplatz zugewiesen. Endet der Aufruf, wird seine Verbindung zu diesem Speicherbereich wieder getrennt und die Speicherverwaltung von JavaScript kann ihn löschen.
- Block Scope
- JavaScript-Anweisungen lassen sich zu Anweisungsblöcken zusammenfassen. Das benötigt man für die Ablaufsteuerung im Programm. Ursprünglich hat JavaScript für Anweisungsblöcke keinen eigenen Scope gebildet. Deswegen liegen
var
-Deklarationen niemals in einem Block Scope, sondern gehören zum Function-, Module- oder Global-Scope. In ECMAScript 2105 (ES6) kam der Block-Scope hinzu. Eine Variable, die mitconst
oderlet
deklariert wird, befindet sich im Block-Scope und verliert ihre Gültigkeit, sobald der zugehörige Anweisungsblock endet.
Da der Scope von Modulen, Funktionen und Blöcken durch den Ort bestimmt wird, an dem diese Programmteile aufgeschrieben sind, spricht man hier auch von lokalen Scopes.
Variablen, Namen und Bindung
Die Existenz mehrerer Scopes, die dazu auch noch ineinander geschachtelt sein können, wirft mehrere Fragen auf. Eine davon ist: Was geschieht, wenn eine Variable in mehr als einem Gültigkeitsbereich deklariert wurde?
Um das zu beantworten, muss man zwischen Namen und Variablen unterscheiden. Wenn man im globalen Scope eine Variable xyz
deklariert, dann gibt es in dem Speicherbereich, der zum globalen Scope gehört, eine Variable, und JavaScript ordnet ihr den Namen xyz
zu. Das ist die Bindung des Namens an die Variable.
Wenn Sie eine Funktion erstellen und zu Beginn eine Variable xyz
deklarieren, dann machen Sie JavaScript bekannt, dass es in dieser Funktion den Namen xyz einer Variablen mit Function Scope zuordnen soll. In dem Moment, wo die Funktion aufgerufen wird, reserviert JavaScript Speicherplatz und schafft damit Platz für die Variablen, die für den Function Scope deklariert wurden.
Während die Funktion läuft, gibt es für den Namen xyz
zwei Variablen. Eine davon liegt im Global Scope, ist aber während der Funktionsausführung nicht sichtbar, weil ihr Name innerhalb der Funktion an eine lokale Variable gebunden wurde. Programmcode, der außerhalb dieser Funktion aufgeschrieben ist, verwendet diese Bindung nicht.
Eine tiefergehende Diskussion dieses Thema muss dem Artikel über Funktionen vorbehalten bleiben. Auf eine Frage soll aber noch eingegangen werden: Was ist, wenn ich in einem lokalen Scope einen Namen definiert habe, der einen Namen im globalen Scope überdeckt - aber trotzdem den Bedarf habe, auf die globale Variable zuzugreifen?
Globaler Scope - Globales Objekt
Der Begriff des Objekts ist bisher noch nicht richtig definiert worden. Merken Sie sich einstweilen nur, dass ein Objekt ein Speicherbereich ist, in dem Sie Werte unter einem Namen ablegen können. Die so erstellten Einträge in diesem Speicherbereich nennen sich Eigenschaften.
Objekteigenschaften und Variablen sind sich also ziemlich ähnlich. Der Hauptunterschied ist, dass JavaScript einen Namen an Hand des Scopes automatisch an eine Variable bindet. Um auf eine Eigenschaft zuzugreifen, müssen Sie das Objekt, in dem gesucht werden soll, ausdrücklich angeben.
Variablen, die Sie im globalen Scope mit var
deklarieren, werden automatisch als Eigenschaften in einem so genannten globalen Objekt bereitgestellt. Sie können das globale Objekt verwenden, um diese Variablen jederzeit zu erreichen. Der Name für dieses globale Objekt ist unterschiedlich, je nachdem, wo Sie JavaScript ausführen.
var
deklariert.JavaScript in einem Dokument eines Webbrowsers verwendet den Namen window
für das globale Objekt. Außer Ihren selbst deklarierten globalen Variablen befinden sich dort buchstäblich hunderte vom Browser vordefinierte Einträge. Hinzu kommen weitere globale Variablen aus JavaScript-Bibliotheken, die Sie vielleicht nutzen möchten. Der globale Scope ist ein Kollision, die nur darauf wartet, zu passieren, deshalb sollten Sie alles tun, um ihre eigenen Variablen dort herauszuhalten. Wir werden in späteren Artikeln darauf eingehen, wie man dafür vorzugehen hat.
Sie können aus ihrem Dokument-JavaScript noch weitere JavaScript-Umgebungen starten, sogenannte Web Worker. In solchen Umgebungen ist das angezeigte Dokument nicht zugänglich, und das globale Objekt in einem Worker findet sich unter dem Namen self
.
Und schließlich gibt es ein beliebtes Tool, um Serverprogramme in JavaScript schreiben zu können, node.js. Dieses Programm verwendet die JavaScript-Engine „V8“ von Google. In einem node.js-Programm gibt es ebenfalls kein HTML-Dokument, dass gerade angezeigt wird, und kein window-Objekt. Das globale Objekt in node.js nennt sich global
.
Für Programmierer, die eine JavaScript-Funktion erstellen möchten, die in mehr als einer dieser Umgebungen läuft und Werte aus dem globalen Objekt benötigt, ist diese Namensvielfalt ein Problem. Sie müssen entweder drei Versionen ihrer Funktion bereitstellen, oder irgendwie erkennen, in welcher Umgebung die Funktion läuft. Um das Problem zu beheben, wurde ein einheitlicher Zugriff auf das globale Objekt spezifiziert: die Variable globalThis
Es wäre auf den ersten Blick praktischer gewesen, statt eines neuen Begriffs die Variablen window
, global
und self
in allen Ausführungskontexten gleichermaßen bereitzustellen, aber das hätte mit Sicherheit alten Code kaputt gemacht, der nicht erwartet, diese Variablen vorzufinden.
Abzuraten ist von der früher gezeigten Idee, eine Funktion aufzurufen und darin die Kontextvariable this
auszulesen. Außerhalb des strict mode funktioniert das, this
enthält dann das globale Objekt. Aber moderner JavaScript-Code sollte immer im strengen Modus (strict mode) geschrieben werden, und darin funktioniert diese Methode nicht mehr. Verwenden Sie globalThis
.
- Hauptartikel: JavaScript/Scope
umfangreicher Hintergrundartikel zum tieferen Verständnis
Empfehlungen für die Praxis
- Verwenden Sie den strict mode, um durch Tippfehler versehentlich erzeugte globale Variablen auszuschließen.
- Scope (Gültigkeit):
Benutzen Sie Variablen – soweit möglich – lokal und deklarieren Sie auch dort. So wird ihr Script übersichtlicher und leichter zu debuggen.- Deklarieren Sie globale Variablen am Anfang des Scripts mit
-
const
für unveränderliche Konstanten -
let
für Variablen
-
- Halten Sie den globalen Namensraum sauber. Globale Variablen sind dank verschiedener Kapselungs-Techniken seltener erforderlich, als man glaubt, aber wenn es gar nicht anders geht, dann sollten Sie Ihre Variablen in einem Namensraum-Objekt zusammenfassen. In dessen Eigenschaften können Sie globale Informationen für Ihr Projekt ablegen.
- lokale Variablen können Sie mit const oder let deklarieren.
- Deklarieren Sie globale Variablen am Anfang des Scripts mit
- Variablennamen
Benutzen Sie sprechende Namen, d. h. sinnvolle Bezeichnungen, die sich später zurückverfolgen lassen.ausgabe = breite * höhe;
ist besser alsa = b * h;
- Achten Sie bei den Namen für Ihre eigenen Variablen und Funktionen aber darauf, dass es sich dabei nicht um bekannte Namen aus den Programmierschnittstellen des Browsers handelt. Damit senken Sie die Gefahr von Namenskollisionen.
- Beachten Sie die Regeln für selbstvergebene Namen, z.B:
- Variablen sind case-sensitive, also achten Sie immer auf Groß-und Kleinschreibung.
- CamelCase
Besser lesbar ist das so genannte CamelCase, in dem die ersten Buchstaben der einzelnen Bestandteile des Namens groß geschrieben werden.
Weblinks
- ↑ SELF:Forum: const in CAPITALS? vom 06.01.2021