Orlok: Konstanten

Beitrag lesen

Hallo @Auge

Meine Fresse! Deine Antworten sind wieder einmal mehrere eigene Wiki-Artikel.

Naja, nicht wirklich. Im Wiki würde ich das Ganze wohl noch etwas detaillierter beschreiben. Das ist ein komplexes Thema und ich habe mich hier in den Postings eigentlich ohne größere Ausschweifungen nur mit den wesentlichsten Aspekten befasst. Glaube ich. :-)

(function test (condition) {
  // function environment
  const number = 8;
  if (condition) {
    // block environment
    const number = 64;
    console.info(number); // 64
  }
  console.info(number); // 8
}(true));

… Mit let und const ist es hingegen möglich, im selben Ausführungskontext eine Kette von Gültigkeitsbereichen zu implementieren.

Offensichtlich bin ich einer Fehlinterpretation des Begriffs const aufgesessen. Es handelt sich zwar um eine Konstante, sie ist aber über die erneute Deklaration änderbar. Das ist ein anderes Verhalten als bei PHP, wo eine Konstante, wenn sie einmal gesetzt und mit einem Wert versehen wurde, bis zum Ende des Skriptlaufs unveränderbar ist.

Ich habe von PHP nicht den blassesten Schimmer, aber soweit ich das beurteilen kann, haben Konstanten in PHP und JavaScript, von der Syntax einmal abgesehen, nicht viele Gemeinsamkeiten. Was wohl schon damit losgeht, dass eine Deklaration mittels const innerhalb einer Funktion oder eines Blocks in PHP gar nicht erlaubt ist, sondern nur Top Level oder in einer Klasse. Man korrigiere mich wenn ich hier falsch liege. Siehe erster Halbsatz. ;-)

Das heißt, wenn ich es richtig verstanden habe (was wie gesagt fraglich ist), dann ist bei Konstanten in PHP der Gültigkeitsbereich immer der globale Scope beziehungsweise ein definierter Namensraum, auch dann wenn sie, anders als bei den zur Compilezeit angelegten Konstanten die mit const deklariert wurden, zur Laufzeit dynamisch mittels define($name, $value) erzeugt werden, was offenbar die einzige Möglichkeit darstellt, eine Konstante innerhalb einer Funktion oder eines Blocks zu notieren.

// global scope
function create ($condition) {
  if ($condition) {
    define('constant', 16);
  }
}

create(true);

if (defined('constant')) {
  echo constant; // 16
}

Das würde jedenfalls erklären, weshalb du bei der Ansicht des zitierten Codebeispiels von mir zu der Schlussfolgerung gekommen bist, es würde eine einmal deklarierte Konstante geändert, denn nach den Regeln von PHP (von dem Erfordernnis const im globalen Scope zu notieren einmal abgesehen) würde hier tatsächlich dieselbe Konstante redeklariert, da diese grundsätzlich programmweit sichtbar wäre.

Das ist hier aber nicht der Fall, denn bezogen auf den zitierten Beispielcode, werden zwei Konstanten deklariert, die zwar den selben Bezeichner haben, jedoch in unterschiedlichen Gültigkeitsbereichen existieren. Denn Konstanten in JavaScript sind nicht grundsätzlich global, sondern immer nur innerhalb eines bestimmten Codeabschnitts sichtbar, so wie normale Variablen auch.

// global scope
function create (condition) {
  // function scope
  if (condition) {
    // block scope
    const constant = 16;
  }
}

create(true);

console.log(constant); // Reference Error

Wenn wir also mein (hoffentlich korrektes) PHP-Beispiel in JavaScript übersetzen, also in einem Anweisungsblock innerhalb einer Funktion eine Konstante erzeugen und dann versuchen im globalen Scope darauf zuzugreifen, dann wird hier eine Ausnahme geworfen, da die Konstante an die lexikalische Umgebung des Blocks gebunden ist und sie darüber hinaus keinerlei Gültigkeit besitzt.

Das bedeutet auch, dass anders als in PHP, die Konstante constant beim Verlassen des Blocks von der Garbage Collection abgeräumt wird, sofern wie hier keine Referenz darauf besteht, und die Konstante nicht bis zum Ende des Programms weiterexistiert.

// global environment binds Spock
const Spock = 'Vulcan';

if (true) {
  // block environment binds Spock
  const Spock = 'Son of Sarek';
  try {
    // constant of outer environment is referenced
    Spock = null;
  } catch (e) {
    console.error(e); // Type Error - invalid (and illogical) assignment
  }
}

Aber natürlich gilt auch für Konstanten in JavaScript – da besteht kein Unterschied zu PHP – dass sie nach ihrer Deklaration nicht verändert werden dürfen, in dem Sinne, dass ihnen kein anderer Wert zugewiesen werden darf, weshalb Konstanten auch immer direkt bei ihrer Deklaration initialisiert werden müssen. Dabei ist aber wie gesehen stets zu berücksichtigen, dass eine Konstante, so wie andere Variablen auch, nur in der lexikalischen Umgebung sichtbar ist in der sie deklariert wurde.

Bezogen auf das Beispiel oben heißt das, dass zunächst eine Konstante mit dem Bezeichner Spock an die globale lexikalische Umgebung gebunden wird. Beim Eintritt in den Anweisungsblock des Conditional Statements wird jedoch für diesen Block eine neue, eigene lexikalische Umgebung erzeugt (die wir uns der Einfachheit halber als Liste der in diesem Bereich deklarierten Variablen vorstellen), und dort wird ebenfalls eine Bindung für den Bezeichner Spock angelegt, welche die im globalen Kontext deklarierte Konstante gleichen Namens verschattet.

Bei dem auf diese Deklaration folgenden Eintritt in den Anweisungsblock von try wird nun auch wieder eine lokale lexikalische Umgebung erzeugt, die allerdings über keine Bindungen verfügt, da in diesem Block keine Deklarationen vorgenommen werden. Schließlich ist hier nur ein Zuweisungsausdruck (Assignment Expression) notiert, dessen linke Seite aus einer Referenz besteht, die natürlich innerhalb der Umgebung dieses Blocks nicht aufgelöst werden kann.

Die lexikalische Umgebung dieses Anweisungsblocks verfügt jedoch nicht nur über eine (hier leere) Liste der deklarierten Konstanten und Variablen (Environment Record), sondern auch über eine Referenz zu ihrer äußeren Umgebung, welche hier über eine Bindung für den Bezeichner Spock verfügt. Diese Bindung wird also im Ergebnis referenziert und da es sich um eine Konstante handelt, die nicht redeklariert werden darf, wird entsprechend eine Ausnahme geworfen.

Was hier im Beispiel natürlich auch dann passiert wäre, wenn innerhalb des Blocks von if keine Konstante deklariert worden wäre, da in diesem Fall bei der Auflösung des Bezeichners (Identifier Resolution) in der äußeren Umgebung dieses Blocks, also der globalen lexikalischen Umgebung weitergesucht worden wäre, die ebenfalls über eine Bindung für den gesuchten Bezeichner verfügt.

// type error before execution

function Enterprise ( ) {
  const Chekov = 'Павел';
  if (true) {
    console.log(typeof Chekov);
  }
  const Chekov = 'navigator';
}

// no call

Das Gleiche gilt selbstverständlich auch für die mehrfache Deklaration einer Konstanten innerhalb desselben Gültigkeitsbereichs, mit dem Unterschied, dass die Ausnahme hier nicht erst geworfen wird, wenn der Programmfluss den Zuweisungsausdruck erreicht.

Wird also beim Parsen irgendwo im Quelltext eine illegale mehrfach-Deklaration einer Konstante erkannt, wird das Programm sofort terminiert. Dies gilt, wie ich im zweiten Beitrag zu dem Thema schon schrieb, aber auch für Variablen, die mit dem Keyword let deklariert werden.

Schließlich sei noch darauf hingewiesen, dass im Gegensatz zu PHP, in JavaScript nicht nur skalare Werte und Arrays als Wert einer Konstanten erlaubt sind. Hier kann einer Konstanten jeder Wert (und Ausdruck) zugewiesen werden, wobei zu beachten ist, dass wie ich ebenfalls schon schrieb, sich die Unveränderlichkeit (Immutability) nur auf die Bindung von Bezeichner und Wert bezieht, nicht aber auf den Wert selbst.

const ship = true && {
  crew : ['Scotty', 'Sulu']
};

ship.name = 'Enterprise'; // no error

const registry = 1701;
registry += 1; // Type Error

Da nun aber primitive Werte nach ihrer Erzeugung prinzipiell nicht mehr verändert werden können, wird hier bei dem Versuch registry zu manipulieren ein Fehler geworfen. Weil es sich bei dem Wert der ersten Konstante jedoch um ein Object handelt (wozu eben auch Arrays und Funktionen gehören), kann dieser Wert weiterhin verändert werden. Wollte man hier auch das Objekt vor Manipulation schützen, dann müsste man hierfür gesonderte Vorkehrungen treffen (Object.freeze).

Du kannst mit ## ein Element <h2> und mit ### eine <h3> erzeugen. Es gibt keinen Grund, die Überschriften mit Formatierungen nur zu simulieren. Zudem erzeugst du mit einer Überschrift eine ID und somit einem Abschnitt, weil die Überschrift nun mit einem Fragmentbezeichner anspringbar ist.

Vielen Dank für die Info! :-)

Gruß,

Orlok

0 49

Regel in CSS Klasse ändern

Blumentopf
  • css
  • javascript
  1. 1
    Auge
    1. 0
      Gunnar Bittersmann
  2. 0
    Matthias Apsel
    • css
    • jsp
    1. 0
      Auge
      • css
      • javascript
      1. 0
        Matthias Apsel
        1. 0
          Auge
          • sprache
    2. 0
      Matthias Apsel
      1. 0
        Gunnar Bittersmann
        • css
        1. 0
          Matthias Apsel
          1. 0
            Gunnar Bittersmann
  3. 0
    Blumentopf
    1. 0
      Auge
      • css
      • html
      • javascript
      1. 0
        Blumentopf
        1. 0
          Auge
          1. 0
            Blumentopf
            1. 0
              Matthias Apsel
            2. 0
              Auge
              1. 0
                Blumentopf
              2. 0
                Orlok
                1. 0
                  Auge
                  1. 0

                    "Funktion" im Alltag

                    Der Martin
                    • sonstiges
                    1. 0
                      Auge
                      • menschelei
                      • sonstiges
                      1. 0
                        Der Martin
                        1. 0
                          Auge
                          1. 0
                            Der Martin
                    2. 0
                      Tabellenkalk
                      1. 0
                        Der Martin
                    3. 0
                      Der Martin
                      1. 1
                        JürgenB
                        • menschelei
                        • sonstiges
                        1. 0
                          Der Martin
                          1. 0
                            JürgenB
                            1. 0
                              Der Martin
                  2. 4

                    Arraymethoden und anonyme Funktionen

                    Orlok
                    • javascript
                  3. 2

                    const let var

                    Orlok
                    • javascript
                    1. 3
                      Orlok
                    2. 0
                      Auge
                      1. 1

                        Konstanten

                        Orlok
                        • javascript
                        • php
                        1. 0
                          Auge
    2. 0
      Gunnar Bittersmann
      • css
      • internationalisierung
      • javascript
      1. 0
        Gunnar Bittersmann
      2. 0
        Blumentopf
        1. 0
          Der Martin
          1. 0
            Blumentopf
            1. 0
              Der Martin
        2. 0
          Matthias Apsel
          1. 0
            Blumentopf
            1. 0
              Matthias Apsel
        3. 0
          Gunnar Bittersmann