Benutzer:Rolf b/JavaScript Variable

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Editiert: 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 logischer Speicherplatz mit einem (unveränderlichen) Namen und einem Wert, der verändert werden kann.

Für Werte gibt es eine ganze Reihe unterschiedlicher Typen, unter anderem Zahlen, logische Werte oder Zeichenketten. Eine Variable ist nicht auf einen bestimmten Wertetyp festgelegt, sie können in jeder Variable jeden Wertetyp speichern.

In JavaScript gibt es drei Anweisungen, die Variablen erzeugen:

  • let: deklariert eine Variable im Block Scope
  • const: deklariert eine symbolische Konstante. Sie verhält sich wie eine mit let deklarierte Variable, die schreibgeschützt ist.
  • var: deklariert eine Variable global oder im Function Scope

Eine Erklärung zum Unterschied zwischen Block und Function Scope folgt im Abschnitt Gültigkeitsbereiche.

Wenn eine Variable deklariert ist, kann man einen Wert darin ablegen. Dieser Wert bleibt solange in der Variablen verfügbar, bis man ihn durch einen anderen Wert überschreibt, oder die Variable gelöscht wird.

Deklaration

Bevor eine Variable verwendet werden kann, muss sie deklariert werden. Diese Deklaration verfolgt mehrere Zwecke.

  • es soll helfen, Programmfehler durch einen Vertipper in Variablennamen zu vermeiden
  • der Ort der Deklaration legt fest, welche Programmteile auf die Variable zugreifen können und wie lange die Variable existiert
  • die verwendete Deklarationsanweisung legt weitere Regeln für den Zugriff fest

Da ein Behälter immer irgendetwas enthalten muss, und sei es auch nur Luft, sieht JavaScript für Variablen, die man deklariert hat, in denen aber noch nichts gespeichert wurde, den speziellen Wert undefined vor. undefined ist ein JavaScript-Schlüsselwort, das für diesen speziellen Wert steht.

let

Die JavaScript Anweisung let deklariert eine oder mehrere Variablen innerhalb des Anweisungsblocks, in dem die let-Anweisung notiert wird. Steht die let-Anweisung außerhalb jeglicher Anweisungsblocks, ist die Variable nach Ausführung der let-Anweisung überall sichtbar und kann überall verwendet werden.

Um mehrere Variablen in einer let-Anweisung zu deklarieren, trennt man die Namen durch ein Komma.

Beispiel
let alter;
let name, vorname;
Beachten Sie: Eine mit let deklarierte Variable ist erst bekannt, wenn die let Anweisung ausgeführt wurde. Eine vorzeitige Verwendung führt zum Script-Abbruch.
Beispiel

Fehler bei vorzeitiger Verwendung

console.log(alter);    // Abbruch!
let alter;

const

Die JavaScript Anweisung const verhält sich genauso wie let, bis auf einen Unterschied: die so deklarierten Variablen können nicht mehr verändert werden. Man muss ihnen also sofort bei der Deklaration einen Wert geben. Wie das geht, folgt im Abschnitt Initialisierung.

Beachten Sie: Der Schreibschutz gilt nur für die Variable selbst. Enthält die Variable ein Objekt oder ein Array, so sind die Inhalte dieses Objekts oder Arrays nach wie vor änderbar
.

var

Bei var handelt es sich um die ursprüngliche JavaScript-Anweisung zur Deklaration von Variablen, und sie verhält sich etwas anders als let und const. Eine var Deklaration, die außerhalb einer Funktion notiert ist, gilt global. Steht sie innerhalb einer Funktion, gilt sie für die ganze Funktion, in der die var Anweisung notiert ist. Es ist dabei ganz gleich, wo in der Funktion die var-Anweisung steht, sie könnte auch ganz am Ende stehen. Diesen Vorgang nennt man Hebung (engl. hoisting). Das funktioniert, weil JavaScript Ihren Code erst ausführt, nachdem es das vollständige Script eingelesen und zur Ausführung vorbereitet hat.

Beispiel
function test() {
   console.log(alter);      // gibt undefined aus
   console.log(falter);     // Bricht das Script mit ReferenceError ab
   var alter = 3;
}
test();

Das Script würde zunächst undefined ausgeben, weil die Variable alter innerhalb der test()-Funktion zwar deklariert wurde, aber zum Zeitpunkt der Log-Ausgabe noch kein Wert zugewiesen wurde. Die Deklaration wird gehoben, die Wertzuweisung dagegen nicht. Der Versuch, falter zu loggen, bricht das Script mit einem ReferenceError ab, weil eine Variable dieses Namens nicht vorhanden ist.

Zuweisung und Initialisierung

Um sinnvoll mit Variablen arbeiten zu können, muss man Werte in ihnen speichern. Das geschieht mit dem [[JavaScript/Operatoren/Zuweisungsoperator|Zuweisungsoperator] =. Weil es häufig vorkommt, dass man einer deklarierten Variablen gleich einen Wert geben möchte, lassen sich Deklaration und Zuweisung auch kombinieren, man spricht dann von Initialisierung.

Beispiel
// Deklaration und Zuweisung getrennt
let breite;
breite = 300;

// Deklaration und Zuweisung zur Initialisierung zusammengefasst
let alter = 18;

// Initialisierung ist auch möglich, wenn mehrere Variablen auf einmal deklariert werden
let x = 100, y = 200;

Sie können außer Literalen auch einen Ausdruck notieren. In einem solchen Ausdruck können Sie beliebig Literale und andere Variablen verwenden. Die Betonung liegt hier auf andere - es ist nicht sinnvoll, beim Initialisieren der Variablen x die Variable x zu verwenden, weil sie in diesem Moment garantiert den Wert undefined enthält.

Beispiel

Die Beispielvorlage hat keinen Inhalt! Bitte verwenden Sie dafür ausschließlich die vorgegebenen Beispiel-Module!

Die Initialisierung mit einem Ausdruck ist natürlich auch für let<code> und <code>var verwendbar.

Beachten Sie: Die Hebung von Variablen, die mit var deklariert wurden, betrifft nur die Deklaration. Die Initialisierung findet an der Stelle statt, wo die var-Anweisung notiert ist.
Beispiel
function test() {
   var alter = 17;
   console.log(alter);      // gibt 17 aus
   console.log(falter);     // bricht das Script nicht mehr ab, aber gibt undefined aus
   var falter = 92;
   console.log(falter);     // gibt 92 aus
}

Automatische Deklaration bei Zuweisung

Wie gezeigt, ist die Verwendung einer Variablen als Wert ist ohne Deklaration nicht möglich. Anders ist es bei der Zuweisung. Aus historischen Gründen erlaubt JavaScript eine Zuweisung an eine undeklarierte Variable und deklariert sie im Moment der Zuweisung automatisch, was unangenehme Folgen haben kann, weil diese Deklaration global erfolgt (dazu gleich mehr). Mit JavaScript 5 wurde der strikte Modus eingeführt, der dieses Verhalten abschaltet und der für neue Programme dringend empfohlen ist. Im strikten Modus führt jede Verwendung einer undeklarierten Variable zu einem Script-Abbruch.

Variablen und das globale Objekt

Ein Bestandteil der JavaScript-Laufzeitumgebung ist das Globale Objekt. In einer Browser-Umgebung finden Sie dieses Objekt in der Variablen window. Variablen, die Sie auf globale Ebene mit var deklarieren oder die automatisch deklariert wurden, finden Sie als Eigenschaften des window-Objekts wieder.

Bei Variablen, die global mit let oder const deklariert wurden, erfolgt kein Eintrag im globalen Objekt.

Gültigkeitsbereiche

Wenn Sie neu in JavaScript einsteigen und noch nicht wissen, was Anweisungsblöcke oder Funktionen sind, sollten Sie diesen Abschnitt zurückstellen.

Wie eingangs erwähnt, wird durch den Ort der Variablendeklaration festgelegt, welche Programmteile die Variable sehen können und wie lange sie existiert. Diese Sichtbarkeit wird durch so genannte Gültigkeitsbereiche (engl. Scopes) geregelt.

Jedem Anweisungsblock, also Codezeilen, die in geschweifte Klammern eingeschlossen sind, ordnet JavaScript einen solchen Gültigkeitsbereich zu. Diese Zuordnung findet zur Laufzeit statt, nicht nur einmal beim Einlesen des Scripts. Wenn Sie also eine Funktion schreiben, wird bei jedem Aufruf dieser Funktion ihr Gültigkeitsbereich neu erzeugt. Wenn die Funktion endet, endet auch die Lebensdauer dieses Gültigkeitsbereichs, und alle Variablen, die sich darin befinden, werden gelöscht. (Diese Aussage ist nur bedingt korrekt, es würde aber zu weit führen, an dieser Stelle auf Closures und ihre Auswirkungen einzugehen).

Außerdem gibt es noch den globalen Gültigkeitsbereich, der dann verwendet wird, wenn kein Anweisungsblock begonnen wurde.

Bei Gültigkeitsbereichen gibt es zwei Aspekte zu beachten. Zum einen ihre Sichtbarkeit, zum anderen ihre Lebensdauer.


Stellen Sie sich Gültigkeitsbereiche wie einen Stapel Blätter vor - weiße und gelbe. Auf jedem Blatt können Variablennamen und Werte dafür notiert werden. Zu Beginn haben wir nur ein gelbes Blatt - der globale Gültigkeitsbereich.

An jeder Stelle, wo Ihr Programmcode einen Anweisungsblock bildet, wird ein Immer dann, wenn der Programmablauf den Beginn eines Anweisungsblocks passiert, wird eine neues, weißes Blatt auf den Stapel gelegt. Wird eine Funktion aufgerufen, legen wir ein gelbes Papier auf den Stapel.

Wird eine Variable mit let oder const deklariert, wird das auf dem Blatt vermerkt, dass gerade zuoberst liegt. Anders ist es bei einer Deklaration mit var. Dafür wird das oberste gelbe Blatt - ein Funktions-Scope - gesucht, um die Variable darauf zu vermerken. Mit einer Ausnahme: eine var-Deklaration darf eine let- oder const-Deklaration nicht überschreiben. Das ist ein Syntaxfehler, der dazu führt, dass das Script gar nicht erst startet.

Beim Abrufen eines Wertes, der in einer Variablen steht, wird der Stapel von oben nach unten nach dem gewünschten Namen durchsucht. Das klingt aufwänd


Variablendeklarationen mit let oder const erfolgen als neue Zeilen der Tabelle, aber auf dieser neuen Folie. Es sei denn, man deklariert eine Variable, deren Name schon in der Tabelle steht. In diesem Fall wird in der Zeile mit dem vorhandenen Namen ein Stück Papier auf die Folie geklebt, das den Wert aus der unteren Folie verdeckt. Die existierende Variable wird durch die neue Deklaration überlagert. 

Und dann gibt es noch den Fall, dass einer Variablen etwas zugewiesen werden soll, die auf einer tiefer liegenden Folie deklariert ist. Nun kommt der Cutter zum Einsatz. In alle Folien, die über der deklarierenden Folie liegen, wird ein Loch geschnitten, so dass auf

Wird der Anweisungsblock verlassen, wird seine Folie entfernt und weggeworfen. Eventuell aufgeklebte Papierchen verschwinden dabei mit, so dass die alten Werte von überlagerten Variablen jetzt wieder sichtbar werden.

Wird ein Anweisungsblock dadurch betreten, dass eine Funktion aufgerufen wird, bekommt die dafür verwendete Folie ein Lesezeichen. Wird nun während der Funktionsausführung eine Variable mit var deklariert, werden Folien ohne Lesezeichen kurz hochgeblättert, bis das Funktionslesezeichen gefunden ist, und die Variable dort eingetragen.

Beispiel

Gültigkeitsbereiche

let a4breite = 210, a4höhe = 297;
let diagonale = berechneDiagonale(a4breite, a4höhe);

console.log('Die Diagonale hat eine Länge von ' + diagonale + ' mm.');

function berechneDiagonale(breite, höhe)
{
  quadratsumme = breite * breite + höhe * höhe;
  var diagonale = Math.sqrt(quadratsumme);
  return diagonale;
}

In diesem Beispiel kommen zwei Gültigkeitsbereiche vor. Zum einen der globale Bereich. In diesem werden die Variablen breite, höhe und diagonale deklariert. Für der Initialisierung der Variablen diagonale wird die Funktion berechneDiagonale aufgerufen.

Dieser Aufruf legt eine zweite Folie auf, und es finden drei Deklarationen statt:

a4breite
dieser Name ist neu, es wird eine neue Zeile erstellt

a4höhe - ebenfalls neu, es wird eine weitere neue Zeile erstellt diagonale -. diagonale - auch dieser Name existiert schon, es wird ein weiteres Papierchen aufgeklebt

breite dieser Name ist neu, es wird eine neue Zeile erstellt
höhe ebenfalls neu, es wird eine weitere neue Zeile erstellt
diagonale dieser Name existiert bereits auf der unteren Folie. Die Funktionsfolie bekommt also ein Papierchen aufgeklebt

Die Parameter breite und höhe werden nun noch mit den als Argument übergebenen Werten befüllt, und dann beginnt die Ausführung der Funktion. Das erste, was sie antrifft, ist eine Zuweisung an eine undeklarierte Variable. Da der strikte Modus nicht eingeschaltet wurde, bedeutet das: Alle Folien beiseite legen und auf der globalen Folie einen neuen Eintrag für quadratSumme erstellen. Darin wird die Summe der Seitenquadrate gespeichert. In der zweiten Zeile findet eine Zuweisung statt. Zunächst wird der zuzuweisende Wert bestimmt, und dafür wird quadratSumme benötigt. Diese Variable steht auf der untersten Folie und ist nicht überklebt, ihr Wert wird



Das bedeutet, dass man es schon beim Öffnen des ersten Anweisungsblocks mit zwei Gültigkeitsbereichen zu tun hat. Dass ein neuer Gültigkeitsbereich eröffnet wurde, Der Zugriff auf diese Gültigkeitsbereiche erfolgt von i

befindet sich eine Variable in einem Gültigkeitsbereich (engl: Scope). Die bisherigen Beispiele haben Variablen im sogenannten globalen Gültigkeitsbereich erzeugt, das heißt: sie werden deklariert und bleiben vorhanden, bis die HTML Seite, auf der das Script steht, wieder verlassen wird. Eine solche Gültigkeit kann gelegentlich erforderlich sein, in den meisten Fällen ist das aber nicht nötig. Eine globale Gültigkeit bedeutet nämlich auch ein hohes Konfliktpotenzial, sobald man JavaScript-Programme mit mehr als nur einigen Zeilen schreibt. Wären alle Variablen global, müsste man sehr genau Buch führen, welche man wofür verwendet.

{{Beispiel|Programmierung mit globalen Variablen

let breite = 210, höhe = 297;
let diagonale = berechneDiagonale(breite, höhe);

console.log('Die Diagonale hat eine Länge von ' + diagonale + ' mm.');

function berechneDiagonale(breite, höhe)
{
  quadratsumme = breite * breite + höhe * höhe;
  diagonale = Math.sqrt(quadratsumme);
  return diagonale;
}

Die Funktion benötigt zwei Zwischenergebnisse: quadratsumme und diagonale. Diese deklariert sie nicht, wodurch sie automatisch im globalen Gültigkeitsbereich gesucht und bei Bedarf angelegt werden. Was die Funktion nicht weiß: Es gibt schon eine Variable diagonale, die sie einfach mal überschreibt. Auf diese Weise entstehen schwer findbare Programmfehler.

Lokaler Gültigkeitsbereich mit var

Um Abhilfe zu schaffen, erzeugt jede Funktion in JavaScript ihren eigenen Gültigkeitsbereich. Er wird erzeugt, wenn die Funktion aufgerufen wird, und alle Variablen, die innerhalb der Funktion deklariert werden, existieren darin. Außerhalb der Funktion sind diese Variablen nicht sichtbar.

Beispiel

Arbeitsdaten in lokalen Variablen

var breite = 210, höhe = 297;
var diagonale = berechneDiagonale(breite, höhe);

console.log('Die Diagonale eines A4-Blattes beträgt ' + diagonale + ' mm.');

function berechneDiagonale(breite, höhe)
{
  var quadratsumme = breite * breite + höhe * höhe;
  var wurzel = Math.sqrt(quadratsumme);
  return Math.round(wurzel);
}

Die abgeänderte Funktion deklariert die Variablen, die sie für ihre Arbeit braucht, mit var. Die so erzeugten Variablen quadratsumme und diagonale werden dadurch im Gültigkeitsbereich der Funktion erzeugt und verschwinden wieder, sobald die Funktion zum Aufrufer zurückkehrt.

So, wie man auch Funktionen ineinander schachteln kann, sind auch die ihnen zugehörigen Gültigkeitsbereiche ineinander verschachtelt. Damit ist gemeint, dass eine Funktion nicht nur die Variablen nutzen kann, die sie selbst deklariert, sondern auch alle Variablen des Gültigkeitsbereichs, in dem sie definiert wurde.

Lokaler Gültigkeitsbereich mit let oder const

Deklarationen mit let und const gehen noch einen Schritt weiter. Um Variablen sozusagen punktgenau deklarieren zu können, reicht ein Scope auf Funktionsebene nicht aus. Deswegen gelten let und const nur exakt innerhalb des Anweisungsblocks, in dem sie notiert sind.

Beispiel

Block Scope mit let

let quadratSumme = 0;
for (let i=0; i<10; i++) {
   const iQuadrat = i * i;
   quadratSumme = quadratSumme + iQuadrat
}
console.log('Summe der Quadrate von 1 bis 10 ist ' + quadratSumme);

In diesem Beispiel werden der Zähler i und sein Quadrat nur innerhalb der for-Anweisung benötigt. Darum wird iQuadrat innerhalb des Anweisungsblocks für for mit let deklariert. Bei i liegt ein Sonderfall vor. Die Klammern der for-Anweisung bilden für let und const einen eigenen Block, und der eigentliche Anweisungsblock der for-Anweisung ist darin eingeschachtelt.

Dadurch wird im Beispiel mit 3 Gültigkeitsbereichen gearbeitet. iQuadrat befindet sich im Block-Scope des Anweisungsblocks der for-Schleife. i liegt bereits in dessen Eltern-Scope, der von der for-Anweisung implizit gebildet wurde. Und quadratSumme ist im globalen Gültigkeitsbereich deklariert (oder im Funktions-Scope, falls das Beispiel in einer Funktion stehen würde).

Überdecken von Variablen

Neue Möglichkeiten schaffen auch neue Probleme. Betrachten Sie dieses Beispiel:

Beispiel

Block Scope mit let

let summe = 0;
for (let i=0; i<10; i++) {
   let summe = summe + i;
}
console.log('Die Summe ist ' + summe);

Die Ausgabe ist: "Die Summe ist 0". Der Grund dafür ist, dass im Anweisungsblock irrtümlich die let-Anweisung verwendet wird, was eine neue Variable erzeugt. Es ist absolut legitim, in einem Gültigkeitsbereich Variablen zu deklarieren, die genauso heißen wie Variablen, die in einem weiter außen liegenden Gültigkeitsbereich deklariert wurden. Die weiter innen deklarierten Variablen verdecken dann die äußeren und machen sie unzugänglich.

Dieses Verhalten ist gewollt und auch wünschenswert. Man möchte ja gerade erreichen, dass man bei der Verwendung von lokalen Variablen unabhängig von den übergeordneten Gültigkeitsbereichen ist. Variablenzugriff aus dem aktuellen Gültigkeitsbereich hinaus - vor allem aus dem Funktions-Gültigkeitsbereich - sollten stets gut geplant sein und nur mit gutem Grund stattfinden.

Zugriff auf überdeckte Variablen

Grundsätzlich gilt: überdeckte Variablen sind überdeckt und nicht erreichbar.

Es gibt aber Variablen oder Schnittstellen, die vom Browser im globalen Gültigkeitsbereich bereitgestellt werden und relativ gewöhnliche Namen tragen, wie location oder document. Wenn man diese Schnittstellen nicht braucht, ist man leicht versucht, solche Namen auch für lokale Variablen zu verwenden. Schlimmer noch, es könnte passieren, dass eine neue Schnittstelle eingeführt wird, unter einem Namen, den man bisher für frei hielt.

Um dennoch auf solche globalen Objekte zugreifen zu können, stellt JavaScript ein spezielles Objekt bereit, das die globalen Variablen als Objekteigenschaft zur Verfügung stellt. Dieses Objekt findet sich im Browser in der globalen Variablen window. Es ist zwar möglich, aber überhaupt keine gute Idee, eine lokale Variable dieses Namens zu erzeugen.

Wenn Sie im Browser einen Worker (Web oder Service Worker) erzeugen, bekommt er einen eigenen, unabhängigen globalen Gültigkeitsbereich. Diesen erreichen Sie über die globale Variable self. Falls Sie Code haben, der sowohl im normalen Browser-Umfeld wie auch in einem Worker laufen soll, wäre es unpraktisch, zwischen window und self unterscheiden zu müssen. Deshalb wird self auch als Alias von window bereitgestellt.

In node.js, einer anderen JavaScript-Ablaufumgebung, heißt diese spezielle Variable global.

Beachten Sie: Globale Variablen, die Sie mittels var deklarieren, finden Sie auch als Eigenschaften des globalen Objekts wieder. Aber eine mit let oder const deklarierte Variable ist über das globale Objekt nicht erreichbar, auch nicht, wenn die Deklaration im globalen Gültigkeitsbereich stattfand.

Und was tut man, wenn man unbedingt auf das globale Objekt zugreifen muss, aber window oder self nicht erreichbar sind? Vor Einführung des strikten Modus gab es dafür einen Trick. Man rief eine Funktion auf und verwendete darin die spezielle Variable this. Im strikten Modus funktioniert das nicht, dort enthält this entweder null oder ein Objekt, für das die Funktion als Methode aufgerufen wurde. Die Antwort heißt: Wenn Sie sich den Weg verbaut haben, ist er verbaut. Gestalten Sie Ihren Code um. Verwenden Sie keine globale Variable namens window oder self.

var

Durch das Schlüsselwort var wird eine Variable vereinbart. Sie wird damit im aktuellen Scope (zum Beispiel innerhalb einer Funktion) angelegt. Ohne das Schlüsselwort var wird die Variable im globalen Scope erstellt.

Sie kann entweder ohne Wert instantiiert werden:

Beispiel
var alter;

Oder der Anfangswert kann gleich angegeben werden:

Beispiel
var alter = 18;

Anstelle der 18 kann ein beliebiger Ausdruck stehen. Das Schema lautet also:

Beispiel
var Bezeichner = Ausdruck;

Wird ihr anfänglich kein Wert zugewiesen, so ist sie vom Typ undefined. Nachdem eine Variable erstellt wurde, kann mit dem Variablennamen gearbeitet werden. Das Speichern von Werten erfolgt über den Zuweisungsoperator.

Datentypen

Da JavaScript keine starke Typisierung aufweist, können in einer Variable alle Arten von Werten gespeichert werden. Der Typ einer Variable richtet sich daher implizit nach dem Typ des darin gespeicherten Wertes. Gegebenenfalls notwendige Typänderungen werden eigenständig im Hintergrund vorgenommen.

Beispiel
// Berechnung Diagonale A4-Papier
var breite    = 210;
var höhe      = 297;
var diagonale = Math.sqrt(breite * breite + höhe * höhe);
var ausgabe   = 'Eine A4-Papierseite hat eine Diagonale von ' + Math.round(diagonale) + ' mm.';

console.log(ausgabe);

Die Werte für

  • breite, höhe und diagonale sind vom Datentyp number
  • ausgabe enthält einen String; also wird der gesamte Wert zu einer Zeichenkette

So ist zum Beispiel die folgende Anweisung in Javascript möglich, ihr Variablentyp ist string; in vielen anderen Programmiersprachen hätte dies eine Fehlermeldung zur Folge.

Beispiel
 breite = 5 + "px"

Gültigkeitsbereich

Beachten Sie: Beim Arbeiten mit Variablen sucht der Interpreter die Variable zuerst im lokalen und anschließend im übergeordneten bis hin zum globalen Sichtbarkeitsbereich. Handelt es sich um eine Wertabfrage und findet er die Variable nicht, so löst er eine Ausnahme aus. Handelt es sich hingegen um eine Wertzuweisung und existiert die Variable nicht, dann erstellt der Interpreter die nicht existierende Variable automatisch als globale Variable.

Globale Variablen

Globale Variablen sind im gesamten Dokument gültig und stehen jederzeit zur Verfügung. Wenn innerhalb von Funktionen Variablen ohne ein lokal machendes Schlüsselwort (var, let oder const) deklariert werden, dann sind diese Variablen global. Wird eine var Deklaration außerhalb einer Funktion ausgeführt, erzeugt das ebenfalls eine globale Variable.

Beispiel
var diagonale;
var ausgabe;

berechneDiagonale(210, 297);
ausgabe = 'Eine A4-Papierseite hat eine Diagonale von ' + diagonale + ' mm.';

function berechneDiagonale(breite, höhe)
{
  diagonale = Math.sqrt(breite * breite + höhe * höhe);
  diagonale = Math.round(diagonale);
}
In diesem Beispiel sind die Variablen diagonale und ausgabe global.

Technisch gesehen handelt es sich bei globalen Variablen um Eigenschaften eines Objektes, das die Javascript-Laufzeitumgebung bereitstellt. Dieses Objekt dient als Ausgangspunkt für alle Daten eines Javascript-Programms und wird auch oberstes oder Wurzelobjekt genannt. Wird eine globale Variable erzeugt, wird das Wurzelobjekt automatisch um eine Eigenschaft mit diesem Namen erweitert. Lesen von globalen Variablen ist gleichbedeutend mit einem Zugriff auf die gleichnamige Eigenschaft des Wurzelobjekts.

Man kann das Wurzelobjekt nutzen, um sicherzustellen, auf eine globale Variable diesen Namens zuzugreifen. Bei Javascript im Browser ist dieses Objekt in der globalen Variablen window zu finden. In anderen Umgebungen, wie Node.js, kann es z. B. global heißen. Darüber hinaus definieren noch viele Browser die globale Variable self und legen dort eine Referenz auf das globale Objekt ab.

Abzuraten ist von der früher gezeigten Idee, eine Funktion aufzurufen und darin die Kontextvariable this zu verwenden. Neuerer JavaScript-Code sollte immer im strengen Modus (strict mode) geschrieben werden, und darin funktioniert diese Methode nicht mehr.

Beispiel
// Globale Variable
var ausgabe = "Hallo Welt";

// Globale Funktion
function add5(a){return a+5;};

// Abfrage vordefinierter globaler Funktionen. 
alert(alert);
alert(window.alert);
alert(self.alert);

// Abfrage globaler Funktionen
alert(add5);
alert(window.add5);
alert(self.add5);

// Abfrage globaler Variablen
alert(ausgabe);
alert(window.ausgabe);
alert(self.ausgabe);

// Auch möglich aber unsinnig
alert(window.self.ausgabe);
Dieses Beispiel verdeutlicht, das globale Variablen auch gleichzeitig Eigenschaften vom window-Objekt sind.

Lokale Variablen

Lokale Variablen werden innerhalb von Funktionen deklariert. Sie sind nur innerhalb dieser Funktion gültig. Wenn eine Funktion mit Parametern definiert wird, so sind diese Parameter implizit als lokale Variablen definiert und erhalten bei Aufruf automatisch die übergebenen Argumente zugewiesen.

Beispiel
function berechneDiagonale(breite, höhe) {
  var diagonale = Math.sqrt(breite * breite + höhe * höhe);
  return Math.round(diagonale);
}

var ausgabe = 'Eine A4-Papierseite hat eine Diagonale von " + berechneDiagonale(210, 297) + " mm.';
breite, höhe und diagonale sind lokale Variablen in der Funktion berechneDiagonale. Außerhalb der Funktion existiert in diesem Beispiel nur eine globale Variable namens ausgabe.
Beispiel
function berechneWurzel(zahl)
{
  var ergebnis = Math.sqrt(zahl);
  return ergebnis;
}

function berechneDiagonale(breite, höhe)
{
  var diagonale = berechneWurzel(breite * breite + höhe * höhe);
  return Math.round(diagonale);
}
 
var ausgabe = 'Eine A4-Papierseite hat eine Diagonale von ' + berechneDiagonale(210, 297) + ' mm.';
In diesem Beispiel sind zahl und ergebnis lokale Variablen der Funktion berechneWurzel. Sie sind nur innerhalb dieser Funktion sichtbar. Die Variablen breite, höhe und diagonale sind lokale Variablen in der Funktion berechneDiagonale. Im globalen Sichtbarkeitsbereich findet sich nur die Variable ausgabe.
Beispiel
function berechneDiagonale(breite, höhe) {
  function berechneWurzel() {
    var ergebnis = Math.sqrt(breite * breite + höhe * höhe);
    return ergebnis;
  }
 
  var diagonale = berechneWurzel();
  return Math.round(diagonale);
}
 
var ausgabe = "Eine A4-Papierseite hat eine Diagonale von " + berechneDiagonale(210, 297) + " mm.";
In diesem Beispiel wurde die Funktion berechneWurzel innerhalb des Funktionskörpers von berechneDiagonale definiert. Daher sieht die Funktion berechneWurzel auch die lokalen Variablen breite und höhe der Funktion berechneDiagonale und kann somit darauf zugreifen. Die Variable ergebnis bleibt hingegen eine lokale Variable von berechneWurzel und ist auch nur dort sichtbar.

Bei Verwendung geschachtelter Funktionen zeigt es sich, dass Javascript in mehr als nur einem lokalen Kontext nach Variablen sucht. Die Funktion berechneWurzel ist zum einen Träger eines eigenen lokalen Kontextes, ist aber selbst auch Teil des Kontextes von berechneDiagonale und kann darum die lokalen Variablen dieses Kontextes ebenfalls verwenden.

Scope und Hebung

var ist das klassische Javascript Syntaxelement zum Definieren lokaler Variablen. Die Semantik von var-Variablen unterscheidet sich von der gewohnten Semantik in Sprachen wie C oder Java dahingehend, dass solche Variablen keinen Block-Scope kennen. Was mit var vereinbart wird, wird vom JavaScript-Interpreter so behandelt, als hätte diese Vereinbarung am Beginn des Script-Blocks bzw. der Funktion stattgefunden, worin die var-Deklaration steht. Diese Verschiebung des Deklarationspunktes nennt man Hebung (hoisting).

Beispiel
testVar = "abc";

function test() {
   testVar = 17;
   alert(testVar);     // gibt "17" aus
   if (5 > 1) {
      var testVar = 3;
   }
}

test();
alert(testVar);        // gibt "abc" aus, testVar wurde nicht überschrieben
Die Variable testVar ist lokal zur Funktion test(), weil das Hoisting dafür sorgt, dass die Deklaration aus dem if heraus an den Anfang gezogen wird.

Anders verhält sich let. Dieses Schlüsselwort ist mit ECMAScript2016 eingeführt worden, um die in anderen Sprachen bekannte Scope-Semantik auch in ECMAScript nutzen zu können. Mit let definierte Variablen unterliegen nicht der Hebung, und gelten nur in dem Anweisungsblock, in dem sie definiert wurden.

Arbeiten mit Variablen

Der große Vorteil einer Variable ist, dass man ihr etwas zuweisen und damit arbeiten kann. Anstatt also feste Werte im Programm zu verwenden, bezieht man sich auf den Wert, der in einer Variable gespeichert wurde. Hierdurch werden Programme erst flexibel und Funktionen können verallgemeinert werden.

Beispiel
// Fix und nicht flexibel
function berechneDiagonaleVonA4Seite()
{
  return Math.round(Math.sqrt(210 * 210 + 297 * 297));
}

// Flexibel durch Verwendung von Variablen
function berechneDiagonale(breite, höhe)
{
  return Math.round(Math.sqrt(breite * breite + höhe * höhe));
}

var diagonaleVonA4 = berechneDiagonaleVonA4Seite(); // starr
var diagonaleVonA5 = berechneDiagonale(210, 148);   // flexibel und wiederverwendbar
var diagonaleVonA3 = berechneDiagonale(420, 297);   // flexibel und wiederverwendbar

Ein weiterer Vorteil und Nachteil zugleich ist, dass es einer Variable erstmal egal ist, was sie für einen Wert beinhaltet. Dies kann eine Zahl, eine Zeichenkette, ein Array, eine Funktion oder sonstiges Objekt sein. Wenn man hingegen einen bestimmten Typ erwartet, der verarbeitet werden soll, dann muss man unter Umständen zuerst prüfen, ob das Objekt in der Variable kompatibel ist oder konvertiert werden kann.

JavaScript führt eine implizite Typkonvertierung durch, wenn man selber nicht darauf achtet. Kann der Typ für eine bestimmte Operation nicht konvertiert werden, dann wird eine Ausnahme ausgelöst oder es wird ein Standardwert zurückgegeben. Es werden aber auch Funktionen bereitgestellt, um eine explizite Typkonvertierung durchzuführen. Diese geben mehr Kontrolle, wie man auf eine unzureichende Konvertierung reagieren möchte.


Beispiel
var jahrtext = "Wir schreiben das Jahr ";
var jahrzahl = 2012;
var ausgabe  = jahrtext + jahrzahl;

alert(ausgabe); // "Wir schreiben das Jahr 2012"
In diesem Beispiel wird ein numerischer Wert an eine Zeichenkette angehängt.


Empfehlungen für die Praxis

Empfehlung:
  • 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 var.
    • Halten Sie den globalen Namensraum sauber. Jedes Programm benötigt einen gewissen Stamm an globalen Daten, es ist aber hilfreich, diese nicht in mehreren Variablen zu verteilen. Nutzen Sie statt dessen eine einzige globale Variable und speichern Sie dort ein Namensraum-Objekt. In dessen Eigenschaften können Sie globale Informationen für Ihr Projekt ablegen.
    • lokale Variablen können Sie mit let deklarieren.
  • Variablennamen
    Benutzen Sie sprechende Namen, d.h. sinnvolle Bezeichnungen, die sich später zurückverfolgen lassen.
    ausgabe = breite * höhe; ist besser als a = b * h;
  • 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.