Funktionen und Zuweisungen in JavaScript
Funktionen als Einträge
Der Ausdruck »this.Math.random« bringt zum Ausdruck, daß die Funktion »random« als ein Eintrag des Verzeichnisses »this.Math« angesehen wird.
Für solche an Funktionen gebundenen Einträge gilt alles, was wir bisher über Einträge gelernt haben.
Wir beobachten beispielsweise zunächst, daß wir die Funktion »random« nicht aufrufen können, ohne »Math« davorzuschreiben.
- Auswertung (übersetzt)
random()
ReferenzFehler: random ist nicht definiert
Wir können Funktionen auch zum Wert anderer Einträge machen. Beispielsweise können wir die Funktion »this.Math.random« zum Wert von »this.random« machen.
- Auswertung
this.random = this.Math.random
Danach ist der Aufruf ohne weitere Qualifikation möglich.
- Auswertung
random()
0.5457413495897813
Kontexte
Wir betrachten nun die folgenden beiden Aufrufe (nach »this.random = this.Math.random«).
- Auswertung
Math.random()
0.7813414549357958
- Auswertung
this.random()
0.4135795845497813
Der Kontext (das Ziel oder Zielverzeichnis) des ersten Aufrufs ist »Math«, der Kontext des zweiten Aufrufs ist »this«.
Eindeutschungen
Das nächste Beispiel zeigt die „Eindeutschung“ des Funktionsnamens.
- Auswertung
Math.zufall = Math.random
Danach ist der Aufruf von »Math.zufall« möglich.
- Auswertung
Math.zufall()
0.285659895756387
Wenn eine Funktion so wie hier zum Wert mehrerer verschiedener Einträge gemacht wird, dann ist dieselbe Funktion in beiden Einträgen enthalten. Weil eine Funktion, wie auch ein Verzeichnis, in mehreren Einträgen enhalten sein kann, ist es nicht nötig sie dafür jedes Mal zu kopieren, und so kosten die neuen Einträge für die Funktion nur relativ wenig zusätzlichen Speicherplatz.
Wenn hervorgehoben werden soll, daß eine Funktion ein Eintrag in einem Verzeichnis ist, so wird sie auch als Methode jenes Verzeichnisses bezeichnet. Alle bisher vorgestellten Funktionen sind Methoden in diesem Sinne, Wir werden später aber auch noch Funktionen kennenlernen, die keine Methoden sind.
Es ist im allgemeinen nicht zu empfehlen, vorhandene Standardverzeichnisse, wie »Math«, um Einträge zu erweitern. Beispielsweise kann dies zu Konflikten führen, wenn diese Verzeichnisse in späteren JavaScript -Versionen mit gleichnamigen Einträgen erweitert werden. Hier soll nur gezeigt werden, daß solche Erweiterungen grundsätzlich möglich sind.
Funktionen als Verzeichnisse
Wir hatte schon festgestellt, daß eine Funktion – wie auch ein Verzeichnis – in mehreren Einträgen enthalten sein kann.
Der Vergleich mit einem Verzeichnis war aber zu schwach. Tatsächlich ist jede Funktion auch ein Verzeichnis.
Funktionen sind Verzeichnisse.
Wir können dies beispielsweise daran erkennen, daß wir eine Funktion mit einem Kommentar versehen können.
- Auswertung
Math.random.kommentar = "Liefert eine Zufallszahl"
"Liefert eine Zufallszahl"
Die Funktion kann danach wie bisher verwendet werden.
- Auswertung
Math.random()
0.495752858635987
Außerdem können wir aber auch noch die mit der Funktion gespeicherten Einträge abrufen.
- Auswertung
Math.random.kommentar
"Liefert eine Zufallszahl"
Jede Funktion ist ein Verzeichnis, aber nicht jedes Verzeichnis ist auch eine Funktion.
Die Einträge von Verzeichnissen sind in der Regel nicht geeignet, um sich darin dauerhafte Notizen abzuspeichern, da sie in der Regel spätestens mit dem Neustart der JavaScript -Implementation wieder verloren gehen, und man dann nur noch die vordefinierten Standardeinträge wiederfindet.
Die meisten Funktionen enthalten ihren Namen als Eintrag »name«.
- Auswertung
Math.random.name
"random"
Der Name, welcher im Eintrag »name« einer Funktion gespeichert wird, wird hier auch als innerer Name der Funktion bezeichnet. Er muß nicht unbedingt immer einem äußeren Namen der Funktion gleichen, also einem Namen, der als Funktionsname in einem Aufrufausdruck zu jener Funktion vorkommt (ein Beispiel dazu folgt weiter unten).
Wir haben schon gesehen, daß wir eine Funktion auch an einen anderen Eintragsnamen binden können und die Funktion dann auch unter Verwendung jenes anderen Eintragsnamens aufrufen können.
- Auswertung
Math.zufall = Math.random
- Auswertung
Math.zufall()
0.969755289586387
Der innere Name der Funktion (der Wert des Eintrags »name« der Funktion) wurde dabei aber nicht geändert.
- Auswertung
Math.zufall.name
"random"
Wir können den Namen auch nicht ändern, denn es handelt sich um einen nicht -änderbaren Eintrag. Beim Versuch einer Änderung gibt es zwar keine Fehlermeldung, aber, wenn man den Namen danach abfragt, sieht man weiterhin den alten Namen.
- Auswertung
Math.random.name = "zufall"
"zufall"
- Auswertung
Math.random.name
"random"
Wir können aber einen neuen Eintrag »Name« (mit großem „N“) anlegen.
- Auswertung
Math.random.Name = "zufall"
"zufall"
- Auswertung
Math.random.Name
"zufall"
Nun erscheint der neue Name auch, wenn die Funktion über den Eintrag »zufall« aufgerufen wird.
- Auswertung
Math.zufall.Name
"zufall"
Weil eine Funktion ein Verzeichnis ist, gilt alles bereits für Verzeichnisse Gesagte auch für Funktionen.
Speicherung von Ergebnissen
Wir können Ergebnisse von Aufrufen natürlich in einem Eintrag speichern.
- Auswertung
v = this.Math.random()
0.578628221
- Auswertung
v
0.578628221
- Auswertung
v
0.578628221
Speicherung von Pfeilfunktionen
Auch Pfeilfunktionen lassen sich in einem Eintrag speichern und so später wieder aufrufen, ohne daß ihre Definition dabei jedesmal wiederholt werden muß.
- Auswertung
f = ()=> 3
function f()
- Auswertung
f
function f()
- Auswertung
f()
3
Solch eine Zuweisung einer (bisher) anonymen Pfeilfunktion an einen Schlüssel nennen wir auch eine Funktionsdefinition.
(Daneben gibt es in JavaScript aber auch noch andere Arten von Funktionsdefinitionen, die wir später noch kennenlernen werden.)
Bindung
Wir weisen ein Verzeichnis dem Schlüssel »f« zu.
- Auswertung
f = ()=> 3
function f()
Nun weisen wir den Wert von »f« dem Schlüssel »g« zu.
- Auswertung
g = f
function f()
Jetzt ändern wir das Verzeichnis »f«, indem wir einen Eintrag »a« anlegen.
- Auswertung
f.a = 27
27
Wir können so erkennen, daß der Name »g« für das gleiche Verzeichnis steht.
- Auswertung
g.a
27
Die Zuweisung eines Verzeichnisses an einen Namen wird auch als Bindung des Verzeichnisses an den Namen bezeichnet, um damit auszudrücken, daß ein und dasselbe Verzeichnis auch an mehrere Namen gebunden werden kann.
(Dieser Alias-Effekt wurde schon früher einmal behandelt.)
Wir haben oben ein Verzeichnis also an die Namen »f« und »g« gebunden.
Auch der Gleichheitsoperator bestätigt die Gleichheit der Bindungen von »f« und »g«.
- Auswertung
f === g
true
Innere Benennung durch Zuweisung
Wenn eine Funktion noch keinen inneren Namen hat und an einen Eintrag gebunden wird, so wird dadurch auch ihr innerer Name auf den Namen des Eintrages gesetzt (ECMAScript 2016, 12.15.4p1.e.)
- Auswertung
x = ()=> 2
function x()
- Auswertung
x.name
"x"
- Auswertung
y = x
function x()
- Auswertung
y
function x()
Diese obenstehende Definition des Attributs »name« kann 2017 erst auf sehr neuen Browsern nachvollzogen werden. Auf weniger neuen Browsern erscheint statt »"x"« die Ausgabe »""«.
Eine zählende Funktion
Bei jedem Aufruf der folgenden Funktion »f« wird der Wert von »a« um »1« erhöht, und der Wert des Aufrufs ist dann dieser neue erhöhte Wert.
- Auswertung
f = ()=> a = a + 1
function f()
- Auswertung
f
function f()
Wenn der Eintrag »a« noch nicht existiert, kann er auch nicht erhöht werden. Daher muß zunächst ein neuer Eintrag angelegt werden. Dabei kann ihr auch gleich ein geeigneter Zahlenwert gegeben werden.
- Auswertung
a + 1
ReferenceError: a is not defined
- Auswertung
a = a + 1
ReferenceError: a is not defined
- Auswertung
f()
ReferenceError: a is not defined
- Auswertung
a = 0
0
- Auswertung
f()
1
- Auswertung
f()
2
- Auswertung
f()
3
Es handelt sich bei »f« um eine Wirkfunktion. (Weil eine Auswertung eines Aufrufs jener Funktion eine Wirkung hat, also etwas [nämlich »a«] verändert.)
Wiederholte Aufrufe derselben Funktionen ⃗
Wenn dieselbe Funktion mehrfach aufgerufen wird, so wird ihr Ausdruck (der Ausdruck hinter »()=>«) bei jedem Aufruf neu ausgewertet. Deswegen erhält man im folgenden Beispiel immer wieder eine andere Zufallszahl.
- Auswertung
f = ()=> this.Math.random()
function f()
- Auswertung
f
function f()
- Auswertung
f()
0.221511580423711
- Auswertung
f()
0.1446199433417
Man kann die obige Folge von Auswertungen mit der folgenden vergleichen: Wenn ein Wert eines Ausdrucks einmal an einen Eintrag zugewiesen wurde, so ändert wird die Auswertung jenes Ausdrucks bei folgenden Verwendungen jenes Eintrages nicht wiederholt.
- Auswertung
x = this.Math.random()
0.04774925622729
- Auswertung
x
0.04774925622729
- Auswertung
x
0.04774925622729
Übungsfragen
? Übungsfrage
Welchen Wert hat der Aufruf »g()« am Ende der folgenden drei Eingaben?
- Eingaben
g = ()=> 2 * f()
f = ()=> 3
g()
? Übungsfrage *
Welchen Ausgabe erzeugt die letzte Zeile der folgenden Eingaben?
- Eingaben
f = x => y => x + " " + y
g = f( "a" )
h = g( "b" )
h
? Übungsfrage **
Welchen Ausgabe erzeugt die letzte Zeile der folgenden Eingaben?
- Eingaben
f = x => y => x + " " + y
g = f( "a" )
h = f( "a" )
g.n = "T"
h.n
Übungsaufgaben
/ Übungsaufgabe
Schreiben Sie eine Funktion »r«, die eine Zufallszahl zwischen 0 (einschließlich) und 1 (ausschließlich) ergibt.
Dabei dürfen andere Funktionen, die in JavaScript vordefiniert sind, aufgerufen werden.
Eine „Funktion »r« zu schreiben“ soll bedeuten, eine Funktion zu schreiben, die dann unter dem Namen »r« erreichbar ist, wie in den folgenden Beispielen gezeigt.
- Auswertung
r()
0.11453489346
- Auswertung
r()
0.09245329016
/ Übungsaufgabe
Schreiben Sie eine Funktion »a«, die eine Zufallszahl zwischen 0 (einschließlich) und 6 (ausschließlich! ) ergibt.
Jeder der Werte «0», «1», «2», «3», «4», und «5» sollte dabei vor dem Komma ungefähr gleich wahrscheinlich sein.
- Auswertung
a()
3.1145176374
- Auswertung
a()
4.0924535925
/ Übungsaufgabe ⃗
Varriieren Sie die Lösung der vorigen Aufgabe so, daß sich eine ganzzahlige Zufallszahl zwischen 0 (einschließlich) und 6 (ausschließlich! ) ergibt.
(Mit einer „ganzzahligen“ Zahl ist hier eine Zahl gemeint, bei der alle Nachkommastellen gleich »0« sind.)
/ Übungsaufgabe ⃗
Varriieren Sie die Lösung der vorigen Aufgabe so, daß sich eine ganzzahlige Zufallszahl zwischen 1 (einschließlich) und 7 (ausschließlich! ) ergibt.