Blumentopf: Regel in CSS Klasse ändern

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

Hallo, ich versuche einen einfachen Language Switch ohne php zu schreiben.

Ich habe zweisprachigen Inhalt auf parallele divs mit unterschiedlichen Klassen verteilt. Nun habe ich folgende Styles definiert:


.en {display:inline;}
.de {display: none;}

per js würde ich nun gerne die Regeln bei Bedarf ändern.

Das versuche ich gerade auf folgende Weise, die leider nicht tut:


		document.styleSheets[0].deleteRule(0);
		document.styleSheets[0].insertRule('.en { display: none; }', 0);

Wahrscheinlich wende ich die Methoden völlig falsch an, habe aber leider nur wenig konkrete Anleitungen dazu gefunden. Vielleicht kann mir jemand da weiterhelfen?

Besten Dank und Grüße

  1. Hallo

    ich versuche einen einfachen Language Switch ohne php zu schreiben.

    Wie wird die zu verwendende Sprache festgelegt? Wie kann sie bei einer Fehlauswahl geändert werden?

    Ich habe zweisprachigen Inhalt auf parallele divs mit unterschiedlichen Klassen verteilt.

    Nun habe ich folgende Styles definiert:

    .en {display:inline;}
    .de {display: none;}
    

    per js würde ich nun gerne die Regeln bei Bedarf ändern.

    Ändere nicht die Regel, ändere eine Angabe im Dokument, so dass andere CSS-Regeln angewendet werden.

      /**
       * Suche das Attribut "lang" im ersten (und dokumentweit einzigen) HTML-Element "html".
       * Erzeuge bei Bedarf das Attribut "lang" und setze oder
       * ändere dessen Wert auf die aktuell zu verwendende Sprache.
       */
    document.getElementsByTagName("html")[0].setAttribute("lang", "de");
    

    Es wird also nur an einer Stelle eine Änderung vorgenommen. Mit einem Set von CSS-Regeln, das je nach HTML-Struktur mehr oder minder groß wird, werden Elemente abhängig von der angegebenen Sprache ein- oder ausgeblendet.

    html[lang=de] .de { display: block; }
    html[lang=de] .en { display: none; }
    
    html[lang=en] .de { display: none; }
    html[lang=en] .en { display: block; }
    

    Tschö, Auge

    --
    Wir hören immer wieder, dass Regierungscomputer gehackt wurden. Ich denke, man sollte die Sicherheit seiner Daten nicht Regierungen anvertrauen.
    Jan Koum, Mitgründer von WhatsApp, im Heise.de-Interview
    1. @@Auge

        /**
         * Suche das Attribut "lang" im ersten (und dokumentweit einzigen) HTML-Element "html".
         * Erzeuge bei Bedarf das Attribut "lang" und setze oder
         * ändere dessen Wert auf die aktuell zu verwendende Sprache.
         */
      document.getElementsByTagName("html")[0].setAttribute("lang", "de");
      

      Nach dem html-Element muss mühsam nicht per getElementsByTagName() im ganzen DOM gesucht werden, sondern das steht mit document.documentElement zur Verfügung.

      Das lang-Attribut gibt die Sprache der gesamten Seite an. Wenn dessen Wert geändert werden soll, stimmt konzeptionell was nicht.

      LLAP 🖖

      --
      “You might believe there are benefits for the developer, but first of all, you should put those behind the interest of the user.” —Stefan Tilkov
      Selfcode: sh:) fo:} ch:? rl:) br:> n4:& va:| de:> zu:} fl:{ ss:| ls:# js:|
  2. Hallo Blumentopf,

    ich versuche einen einfachen Language Switch ohne php zu schreiben.

    Meiner Meinung nach ist keine gute Idee, komplett mehrsprachige Dokumente anzubieten. Besser wäre es zwei verschiedene Dokumente für die Sprache zu haben.

    Falls du es doch so machen möchtest:

    • Ändere per Click und JavaScript das lang-Attribut des html-Elements[1]
    • Verwende keine Klasse en sondern für jedes Element das entsprechende Sprachattribut.
    html:lang=de :lang:not(:lang=de) { display: none; }
    html:lang=en :lang:not(:lang=en) { display: none; }
    

    Wie gesagt, richtig klug finde ich es nicht. en und de sind auch nicht die richtigen Sprachbezeichner

    Bis demnächst
    Matthias

    --
    Wenn eine Idee nicht zuerst absurd erscheint, taugt sie nichts. (Albert Einstein)

    1. Vielleicht ist das aber auch falsch, weil ja beide Sprachen im Dokument stehen. ↩︎

    1. Hallo

      ich versuche einen einfachen Language Switch ohne php zu schreiben.

      Meiner Meinung nach ist keine gute Idee, komplett mehrsprachige Dokumente anzubieten. Besser wäre es zwei verschiedene Dokumente für die Sprache zu haben.

      Ja, zumal sich die Frage nach falsch ausgewählten Sprache(n) stellt (wie ich in meinem Posting schon anklingen ließ). Ein Dokument pro Sprache erscheint mir aber auch der zu beschreitende Weg.

      en und de sind auch nicht die richtigen Sprachbezeichner

      ? Laut der dortigen Übersicht der Sprachenkürzel nach ISO 639-1 sind es genau die richtigen Kürzel.

      Tschö, Auge

      --
      Wir hören immer wieder, dass Regierungscomputer gehackt wurden. Ich denke, man sollte die Sicherheit seiner Daten nicht Regierungen anvertrauen.
      Jan Koum, Mitgründer von WhatsApp, im Heise.de-Interview
      1. Hallo Auge,

        en und de sind auch nicht die richtigen Sprachbezeichner

        ? Laut der dortigen Übersicht der Sprachenkürzel nach ISO 639-1 sind es genau die richtigen Kürzel.

        Ich hatte sowas wie en-US im Sinn.

        Bis demnächst
        Matthias

        --
        Wenn eine Idee nicht zuerst absurd erscheint, taugt sie nichts. (Albert Einstein)
        1. Hallo

          Hallo Auge,

          en und de sind auch nicht die richtigen Sprachbezeichner

          ? Laut der dortigen Übersicht der Sprachenkürzel nach ISO 639-1 sind es genau die richtigen Kürzel.

          Ich hatte sowas wie en-US im Sinn.

          Das ergibt doch nur Sinn, wenn es sich, um bei deinem Beispiel zu bleiben, tatsächlich und explizit um amerikanisches Englisch handelt. Z.B. könnte man mit "de-de" österreichische, schweizerische oder belgische Nutzer unabsichtlich vor den Kopf stoßen.

          Um das Beispiel zu konstruieren:

          Hat der Nutzer keine eigene Sprachauswahl getätigt, versucht das Programm die Sprache anhand der Browservorgaben zu ermitteln und die Inhalte passend vorzugeben. Für die Ausgabe der deutschen Sprachteile setzt das Programm die Angabe von "de-de" voraus. Als Standard für nicht vorgegebene oder nicht zur Auswahl stehende Sprachen wird – wegen der weltweit größeren Verbreitung – die englische Sprache ausgegeben. Der Nutzer kommt mit einem Browser, der "de-at" angibt, daher und wird wegen der (angeblich) nicht passenden Sprachangabe auf die englischsprachige Ausgabe geleitet.

          Tschö, Auge

          --
          Wir hören immer wieder, dass Regierungscomputer gehackt wurden. Ich denke, man sollte die Sicherheit seiner Daten nicht Regierungen anvertrauen.
          Jan Koum, Mitgründer von WhatsApp, im Heise.de-Interview
    2. Hallo Matthias Apsel,

      html:lang=de :lang:not(:lang=de) { display: none; }
      html:lang=en :lang:not(:lang=en) { display: none; }
      

      Syntaxkorrektur

      html:lang(de) [lang]:not(:lang(de)) { display: none; }
      html:lang(en) [lang]:not(:lang(en)) { display: none; }
      

      Nachfahren des html-Elements mit lang-Attribut, die ihrerseits ein lang-Attribut besitzen, welches nicht den entsprechenden Wert hat.

      Aber wie gesagt, ich halte das Prinzip für falssch,

      Bis demnächst
      Matthias

      --
      Wenn eine Idee nicht zuerst absurd erscheint, taugt sie nichts. (Albert Einstein)
      1. @@Matthias Apsel

        html:lang(de) [lang]:not(:lang(de)) { display: none; }
        html:lang(en) [lang]:not(:lang(en)) { display: none; }
        

        Das kann so nicht richtig sein.

        <html lang="de"><div lang="de"><p>Das war ein <i lang="fr">faux pas</i>, nicht wahr?</p></div></html> 
        

        Gerendert wird: Das war ein , nicht wahr?

        LLAP 🖖

        --
        “You might believe there are benefits for the developer, but first of all, you should put those behind the interest of the user.” —Stefan Tilkov
        Selfcode: sh:) fo:} ch:? rl:) br:> n4:& va:| de:> zu:} fl:{ ss:| ls:# js:|
        1. Hallo Gunnar Bittersmann,

          Das kann so nicht richtig sein.

          <html lang="de"><div lang="de"><p>Das war ein <i lang="fr">faux pas</i>, nicht wahr?</p></div></html> 
          

          Laut Beschreibung kommt diese Konstellation nicht vor. Es ist aber ein weiteres Beispiel für die Untauglichkeit des Konzepts.

          Bis demnächst
          Matthias

          --
          Wenn eine Idee nicht zuerst absurd erscheint, taugt sie nichts. (Albert Einstein)
          1. @@Matthias Apsel

            Laut Beschreibung kommt diese Konstellation nicht vor.

            In der Beschreibung steht nirgends, dass in den deutschen bzw. englischen Blöcken nicht auch anderssprachige Abschnitte (bspw. Zitate) oder Phrasen vorkommen (deren Sprache selbsteverständlich entsprechend gekennzeichnet wird).

            Es ist aber ein weiteres Beispiel für die Untauglichkeit des Konzepts.

            Abhilfe schafft die Kennzeichnung der umzuschaltenden Bereiche als solche, bspw:

            <div class="lang-switch-container" lang="de"></div>
            <div class="lang-switch-container" lang="en"></div>
            
            html:lang(de) .lang-switch-container:not(:lang(de)) { display: none; }
            html:lang(en) .lang-switch-container:not(:lang(en)) { display: none; }
            

            Was das Konzept als solches nicht unbedingt besser macht.

            Bei Umschaltung der Sprache wäre zumindest assistiver Technologie (wie Screenreadern) mitzuteilen, dass sich die Sichbarkeit der Inhalte geändert hat.

            LLAP 🖖

            --
            “You might believe there are benefits for the developer, but first of all, you should put those behind the interest of the user.” —Stefan Tilkov
            Selfcode: sh:) fo:} ch:? rl:) br:> n4:& va:| de:> zu:} fl:{ ss:| ls:# js:|
  3. Vielen Dank für die schnellen Antworten!

    Ich habe zunächst versucht Auges Vorschlag umzusetzen. Zu deiner Frage: Oben auf der Seite gibt es einen Link zum Umschalten. Damit das über alle zugehörigen Seiten konsistent bleibt, wird ein Cookie gesetzt, und anschließend ausgelesen. Anschließend wird je nach Inhalt des Cookies die Sprache gesetzt.

    Mit Auges Methode funktioniert die Sprachwahl momentan nur beim Neuladen der Seite, nicht aber per späterem Klick. Das lang Attribut wird dann zwar noch geändert, der angezeigte Text passt sich aber nicht mehr an.

    So sieht das bei mir im Moment aus:

      <script>
    document.getElementsByTagName("html")[0].setAttribute("lang", "de");
    
    alert(document.getElementsByTagName("html")[0].lang);
    
    	function cookie(l) {
    	var cookie = "lang=; path=/;expires=Thu, 18 Dec 1913 12:00:00 UTC;";
    	document.cookie = cookie;
    	
    	var cookie = "lang=" + l + "; path=/;expires=Thu, 18 Dec 2019 12:00:00 UTC;";
    	document.cookie = cookie;
    	lang();
    	
    	}
    
    	function lang() {
    	if (document.cookie == "lang=de") {
    		document.getElementsByTagName("html")[0].setAttribute("lang", "de");
    alert('deutsch, cookie: ' + document.cookie + ' lang=' + document.getElementsByTagName("html")[0].lang);
    		}
    	else if (document.cookie == "lang=en") {
    		document.getElementsByTagName("html")[0].setAttribute("lang", "en");
    		alert('englisch, cookie: ' + document.cookie + ' lang=' + document.getElementsByTagName("html")[0].lang);
    		}
    
    	}	
      </script>
    

    Bezüglich der Frage, ob es sinnvoll ist, beide verwendeten Sprachen in einem Dokument unterzubringen, möchte ich ergänzen, dass die Seite nur sehr wenig Text enthält, und ich es daher für effiezienter halte, das alles einzubinden, als Seiten neu zu laden.

    Wo wäre folgender Text von Matthias genau zu notieren?

    html:lang=de :lang:not(:lang=de) { display: none; }
    html:lang=en :lang:not(:lang=en) { display: none; }
    

    Beste Grüße

    1. Hallo

      Ich habe zunächst versucht Auges Vorschlag umzusetzen. Zu deiner Frage: Oben auf der Seite gibt es einen Link zum Umschalten. Damit das über alle zugehörigen Seiten konsistent bleibt, wird ein Cookie gesetzt, und anschließend ausgelesen. Anschließend wird je nach Inhalt des Cookies die Sprache gesetzt.

      Was passiert, wenn ich den Link benutze/klicke? Ich sehe zwar die Definitionen der Funktionen in deinem Code, aber nicht deren Aufruf.

      Mit Auges Methode funktioniert die Sprachwahl momentan nur beim Neuladen der Seite, nicht aber per späterem Klick. Das lang Attribut wird dann zwar noch geändert, der angezeigte Text passt sich aber nicht mehr an.

      Wenn sich der Wert des Attributs tatsächlich ändert, sollten auch die passenden Regeln greifen. Was sagen die Entwicklerwerkzeuge deines Browsers?

      Wo wäre folgender Text von Matthias genau zu notieren?

      html:lang=de :lang:not(:lang=de) { display: none; }
      html:lang=en :lang:not(:lang=en) { display: none; }
      

      Natürlich in der CSS-Datei. Die Regeln greifen bei Elementen, die Kind von <html> (mit einer passenden Angabe im Lang-Attribut) sind und ihrerseits über ein passendes Lang-Attribut verfügen.

      <!DOCTYPE html>
      <html lang="de">
       <!-- bla bla bla -->
        <p lang="de">Kikeriki …</p>
        <p lang="en">cock-a-doodle-doo …</p>
       <!-- blubb blubb blubb -->
      

      Tschö, Auge

      --
      Wir hören immer wieder, dass Regierungscomputer gehackt wurden. Ich denke, man sollte die Sicherheit seiner Daten nicht Regierungen anvertrauen.
      Jan Koum, Mitgründer von WhatsApp, im Heise.de-Interview
      1. Was passiert, wenn ich den Link benutze/klicke? Ich sehe zwar die Definitionen der Funktionen in deinem Code, aber nicht deren Aufruf.

        Das ist der Link:

        <span class="lang de"><a href=javascript:cookie('en');>english</a></span>
        <span class="lang en"><a href=javascript:cookie('de');>deutsch</a></span>
        

        im CSS steht momentan noch:

        html[lang=de] .de { display: inline; }
        html[lang=de] .en { display: none; }
        
        html[lang=en] .de { display: none; }
        html[lang=en] .en { display: inline; }
        
        

        Grüße

        1. Hallo

          Was passiert, wenn ich den Link benutze/klicke? Ich sehe zwar die Definitionen der Funktionen in deinem Code, aber nicht deren Aufruf.

          Das ist der Link:

          <span class="lang de"><a href=javascript:cookie('en');>english</a></span>
          <span class="lang en"><a href=javascript:cookie('de');>deutsch</a></span>
          

          Ja, schön. Meine Frage, besonders die folgende Zusatzfrage, bezog sich darauf, ob denn neben dem Cookie auch der Wert des Lang-Attributs passend verändert wird. Soweit ich mich an das Cookie-Handling von PHP erinnere, steht der neue Wert PHP erst nach einem Reload der Seite zur Verfügung. Nun funktioniert JavaScript clientseitig. Du setzt den Cookie im Browser vom Dokument aus. Er könnte einem Skript im Dokument also danach sofort seinen neuen Wert zur Verfügung stellen. Ob das tatsächlich so funktioniert, kann ich auf die Schnelle nicht prüfen. Es könnte also sein, dass das Verhalten dem bei PHP ähnelt.

          Wenn der neue Cookie-Wert nicht sofort nach dem Setzen des Werts verfügbar ist, solltest du den Wechsel des Attributwerts in der Funktion lang() nicht vom Wert im Cookie sondern vom Klickwert abhängig machen.

          Tschö, Auge

          --
          Wir hören immer wieder, dass Regierungscomputer gehackt wurden. Ich denke, man sollte die Sicherheit seiner Daten nicht Regierungen anvertrauen.
          Jan Koum, Mitgründer von WhatsApp, im Heise.de-Interview
          1. Wenn der neue Cookie-Wert nicht sofort nach dem Setzen des Werts verfügbar ist, solltest du den Wechsel des Attributwerts in der Funktion lang() nicht vom Wert im Cookie sondern vom Klickwert abhängig machen.

            Der Cookie-Wert ist sofort verfügbar, das habe ich mit dem alert überprüft. Auch das lang Attribut wird wie gewünscht geändert. Die Ausgabe von

            alert('cookie: ' + document.cookie + ', html: lang=' + document.getElementsByTagName("html")[0].lang);
            
            

            lautet:

            cookie: lang=en, html: lang=en
            

            Nun müsste ich wahrscheinlich das Neu Rendern der Seite herbeiführen, um die Änderung auch sichtbar zu machen.

            Wenn ich die Funktion

            lang(); 
            

            beim Laden aufrufe, ist die zuvor getätigte Sprachwahl auch sichtbar. Ich müsste also entweder beim Klicken auf den Link auch das Neuladen erzwingen, oder eine andere Methode zum Neurendern finden, falls es die gibt. Vom Prinzip ist das mit dem Neuladen ja ok, ich hätte es nur eleganter gefunden, darauf verzichten zu können, gerade in Hinblick auf mögliche mobile Nutzer.

            Aber als elegant scheint mein Ansatz hier ja ohnehin nicht durchzugehen :)

            1. Hallo Blumentopf,

              Auch das lang Attribut wird wie gewünscht geändert.

              Du benötigst lediglich für das Ändern des lang-Attributes (und für das Setzen des Cookies) JavaScript. Die zwei Zeilen CSS sollten in der CSS-Ressource vorhanden sein

              Ich müsste also entweder beim Klicken auf den Link auch das Neuladen erzwingen, oder eine andere Methode zum Neurendern finden, falls es die gibt.

              und die Änderungen auch sofort sichtbar sein.

              Aber als elegant scheint mein Ansatz hier ja ohnehin nicht durchzugehen :)

              Das lang-Attribut des html-Elements gibt an, in welcher Sprache (der Großteil) des Dokuments vorliegt. Du hast aber mehrere Sprachen.

              Bis demnächst
              Matthias

              --
              Wenn eine Idee nicht zuerst absurd erscheint, taugt sie nichts. (Albert Einstein)
            2. Hallo

              Die Ausgabe von

              alert('cookie: ' + document.cookie + ', html: lang=' + document.getElementsByTagName("html")[0].lang);
              

              lautet:

              cookie: lang=en, html: lang=en
              

              Nun müsste ich wahrscheinlich das Neu Rendern der Seite herbeiführen, um die Änderung auch sichtbar zu machen.

              Nein. Wird der Wert von lang im DOM geändert, ist diese Änderung real und es werden andere CSS-Regeln gültig, wenn sie denn zutreffen. Ich nehm' mal ein Beispiel von mir. Das mag nicht unbedingt elegant sein, aber es funktioniert. Zum herumspielen sollte das Skript jedenfalls reichen.

              
              /**
               * warte, bis das DOM geladen ist
               */
              window.addEventListener("DOMContentLoaded", start, false);
              
              /**
               * registriere den Event-Listener für das aside #function_bar,
               * das ein Formular enthält, welches wiederum Buttons enthält
               */
              function start() {
              var listen2Click = document.getElementById("function_bar");
              listen2Click.addEventListener("click", switchClass, false);
              listen2Click.setAttribute("class", "js");
              }
              
              /**
               * Nachimplementation der PHP-Funktion in_array() (Helferfunktion)
               */
              function inArray(item, array) {
              var arrayLen = array.length;
              for (p = 0; p < arrayLen; p++) { if (array[p] == item) return true; }
              return false;
              }
              
              /**
               * Werte den erfolgten Klick aus, vergleiche den Wert des
               * geklickten Buttons mit den erlaubten Werten (Variable `possTargets`)
               * und weise den Wert des Buttons, wenn er nach der Prüfung mit in_array()
               * als erlaubt gilt, als Klassenname dem HTML-Element „body“ zu.
               */
              function switchClass(e) {
              if (!e) e = window.event;
              var klickTarget = e.target;
              var targetName = "";
              var possTargets = ["without_rework", "with_rework", "deletions"];
              if (inArray(klickTarget.value, possTargets)) {
              	targetName = klickTarget.value;
              	} else {
              	targetName = "";
              	}
              var htmlBody = document.getElementsByTagName("body");
              //var classValue = htmlBody[0].getAttribute("class");
              if (targetName.length > 0) {
              	htmlBody[0].setAttribute("class", targetName);
              	} else {
              	htmlBody[0].removeAttribute("class");
              	}
              }
              

              Je nach Klassenname werden in meinem Dokument Listenelemente anhand von CSS-Regeln unmittelbar ein- bzw. ausgeblendet. Ein Neuladen oder -rendern des Dokuments ist nicht notwendig.

              .without_rework .need_rework,
              .without_rework .obsolete,
              .with_rework .no_problem,
              .with_rework .obsolete,
              .deletions .no_problem,
              .deletions .need_rework {
              display: none;
              }
              

              Ob nun body das Attribut class mit einem bestimmten Wert zugewiesen bekommt, oder html das Attribut lang mit einem ebenso bestimmten Wert, ist egal. Die konkreten CSS-Regeln werden nach dem Wechsel des Attributwertes (un)wirksam. Die Struktur des HTML-Dokuments muss natürlich so beschaffen sein, dass die CSS-Regeln zutreffen.

              Ich müsste also entweder beim Klicken auf den Link auch das Neuladen erzwingen, oder eine andere Methode zum Neurendern finden, falls es die gibt.

              Wie gesagt, wenn alle beteiligten Techniken zusammenspielen, ist das nicht notwendig.

              Vom Prinzip ist das mit dem Neuladen ja ok, ich hätte es nur eleganter gefunden, darauf verzichten zu können, gerade in Hinblick auf mögliche mobile Nutzer.

              Dann kannst du auch nach Sprachen gleich getrennte Inhalte ausliefern. Bei einer Änderung der Sprachangabe kannst du die neuen Inhalte ohne Reload der ganzen Seite mit AJAX nachladen.

              Aber als elegant scheint mein Ansatz hier ja ohnehin nicht durchzugehen :)

              Nee, elegant ist anders. :-)

              Tschö, Auge

              --
              Wir hören immer wieder, dass Regierungscomputer gehackt wurden. Ich denke, man sollte die Sicherheit seiner Daten nicht Regierungen anvertrauen.
              Jan Koum, Mitgründer von WhatsApp, im Heise.de-Interview
              1. Nein. Wird der Wert von lang im DOM geändert, ist diese Änderung real und es werden andere CSS-Regeln gültig, wenn sie denn zutreffen.

                Gut, dann habe ich wohl irgendwo einen Fehler. Erst beim Neuladen werden bei mir die Änderungen sichtbar.

                Ich habe nun noch ein anderes kleines Problem mit den Cookies. nach einer Weile Hin- und Herschalten tut die Funktion plötzlich nicht mehr. Bei der Abfrage des Cookies wird dann lang=de und lang=en ausgegeben. Lösche ich in den Einstellungen alle Cookies, tut es wieder. Deshalb habe ich eigentlich vor dem Setzen des Cookies versucht, diesen zu löschen, in dem ich ihn nochmals setze und mit abgelaufenem Verfallsdatum versehe.

                var cookie = "lang=; path=/;expires=Thu, 18 Dec 1913 12:00:00 UTC;";
                	document.cookie = cookie;
                	
                	var cookie = "lang=" + l + "; path=/;expires=Thu, 18 Dec 2019 12:00:00 UTC;";
                	document.cookie = cookie;
                

                Das scheint so aber nicht zuverlässig zu funktionieren. Müsste ich statt lang=; jeweils lang=de; und lang=en; schreiben, um den alten expire Wert zu überschreiben?

              2. Hallo Auge

                Ich nehm' mal ein Beispiel von mir. Das mag nicht unbedingt elegant sein, aber es funktioniert. Zum herumspielen sollte das Skript jedenfalls reichen.

                Ich hoffe du nimmst es mir nicht übel, wenn ich dennoch etwas dazu schreibe. ;-)

                /**
                 * warte, bis das DOM geladen ist
                 */
                window.addEventListener("DOMContentLoaded", start, false);
                

                Der dritte Parameter der Methode addEventListener, über den bestimmt werden kann, für welche Ereignisphase der Eventhandler registriert werden soll, ist optional, und der Standardwert für diesen Parameter ist false. Das heißt, wenn kein drittes Argument übergeben wird, dann wird der Eventhandler nicht für die Capturing-Phase registriert.

                window.addEventListener('DOMContentLoaded', start);
                

                Die Browser, bei denen eine explizite Angabe für diesen Parameter notwendig gewesen wäre, dürften mittlerweile wohl schon lange ausgestorben sein. Es ist aber natürlich kein Fehler false anzugeben. Ich wollte nur mal erwähnt haben, dass das eigentlich nicht notwendig ist.

                /**
                 * registriere den Event-Listener für das aside #function_bar,
                 * das ein Formular enthält, welches wiederum Buttons enthält
                 */
                function start() {
                var listen2Click = document.getElementById("function_bar");
                listen2Click.addEventListener("click", switchClass, false);
                listen2Click.setAttribute("class", "js");
                }
                

                Gibt es auch ein aside function_foo? – scnr ;-) Naja, wie auch immer, jedenfalls ist die Verwendung von setAttribute hier nicht wirklich vorbildhaft. Ich hätte das wohl eher so geschrieben:

                function start ( ) {
                  const aside = document.getElementById('function_bar');
                  aside.addEventListener('click', switchClass);
                  aside.classList.add('js');
                }
                

                Es ist meistens die beste Wahl mit classList zu arbeiten, da hierbei nicht das Risiko besteht, dass ein Wert unbeabsichtigt überschrieben wird. Ansonsten wäre hier aside.className='js' ebenfalls eine Alternative.

                /**
                 * Nachimplementation der PHP-Funktion in_array() (Helferfunktion)
                 */
                function inArray(item, array) {
                var arrayLen = array.length;
                for (p = 0; p < arrayLen; p++) { if (array[p] == item) return true; }
                return false;
                }
                

                Wenn es darum geht herauszufinden, ob ein bestimmter Wert in einem Array enthalten ist, dann gäbe es zu diesem Zweck auch in JavaScript eine eingebaute Methode, nämlich Array.prototype.includes.

                console.info( [1, 2, 3].includes(2) ); // true
                

                Je nach dem ob der als Argument übergebene Wert in dem Array ist, wird entweder true oder false zurückgegeben. Dabei wird im Übrigen der Vergleichsalgorithmus SameValueZero verwendet und nicht einfach auf strict equality geprüft. Allerdings, auch wenn includes hier von der Semantik her das Mittel der Wahl sein sollte, muss dennoch erwähnt werden, dass diese Methode noch nicht überall implementiert ist, man also gegebenenfalls ein Polyfill bereitstellen müsste.

                /**
                 * Werte den erfolgten Klick aus, vergleiche den Wert des
                 * geklickten Buttons mit den erlaubten Werten (Variable `possTargets`)
                 * und weise den Wert des Buttons, wenn er nach der Prüfung mit in_array()
                 * als erlaubt gilt, als Klassenname dem HTML-Element „body“ zu.
                 */
                function switchClass(e) {
                if (!e) e = window.event;
                

                In einem Browser der mit dem Ereignismodell des DOM nichts anfangen kann, würde diese Funktion niemals aufgerufen werden. Die Prüfung ob ein Event-Objekt übergeben wurde kann man sich also sparen.

                var klickTarget = e.target;
                

                Zumal du dann hier konsequenterweise als Alternative noch e.srcElement hättest anbieten müssen. ;-)

                var targetName = "";
                var possTargets = ["without_rework", "with_rework", "deletions"];
                if (inArray(klickTarget.value, possTargets)) {
                	targetName = klickTarget.value;
                	} else {
                	targetName = "";
                	}
                

                Ich denke, das geht alles auch ein wenig eleganter, wie du ja selbst schon vermutet hast. Wobei ich bei meiner alternativen Version mal davon ausgehe, dass Array.prototype.includes unterstützt wird, beziehungsweise dass ein Polyfill dafür bereitsteht.

                function switchClass (event) {
                  const value = event.target.value,
                        name = [
                          "without_rework",
                          "with_rework",
                          "deletions"
                        ].includes(value) && value;
                  // ...
                }
                

                Natürlich könnte man der Übersicht zuliebe hier für das Array auch eine Variable anlegen, also das muss nicht zwingend der Weisheit letzter Schluss sein. ;-)

                var htmlBody = document.getElementsByTagName("body");
                

                Die Methode getElementsByTagName muss hier nicht wirklich bemüht werden, da das Body-Element, beziehungsweise seine DOM-Repräsentation über document.body referenziert werden kann.

                //var classValue = htmlBody[0].getAttribute("class");
                if (targetName.length > 0) {
                	htmlBody[0].setAttribute("class", targetName);
                	} else {
                	htmlBody[0].removeAttribute("class");
                	}
                }
                

                Auch das schaut mir ein wenig sehr umständlich aus. Aber wie auch immer, im Folgenden nochmal alles kompakt zusammengefasst.

                window.addEventListener('DOMContentLoaded', function ( ) {
                
                  const aside = document.getElementById('function_bar');
                
                  aside.addEventListener('click', function (event) {
                    const value = event.target.value,
                          list = ['without_rework', 'with_rework', 'deletions'];
                
                    document.body.className = list.includes(value) ? value : '';
                  });
                
                });
                

                Viele Grüße,

                Orlok

                1. Hallo

                  Ich nehm' mal ein Beispiel von mir. Das mag nicht unbedingt elegant sein, aber es funktioniert. Zum herumspielen sollte das Skript jedenfalls reichen.

                  Ich hoffe du nimmst es mir nicht übel, wenn ich dennoch etwas dazu schreibe. ;-)

                  Keineswegs, deine fundierte Art der Kritik ist mir, selbst wenn ich einzelne Punkte anders sehen sollte, stets willkommen.

                  window.addEventListener("DOMContentLoaded", start, false);
                  

                  vs.

                  window.addEventListener('DOMContentLoaded', start);
                  

                  Die Browser, bei denen eine explizite Angabe für diesen Parameter notwendig gewesen wäre, dürften mittlerweile wohl schon lange ausgestorben sein. Es ist aber natürlich kein Fehler false anzugeben. Ich wollte nur mal erwähnt haben, dass das eigentlich nicht notwendig ist.

                  Ich weiß, ich weiß. Da wir beide das schon einmal hatten, hatte ich noch überlegt, das false aus dem Code herauszunehmen. Das hätte dem Forumsarchiv ein paar Kilobyte erspart. :-)

                  /**
                   * registriere den Event-Listener für das aside #function_bar,
                   * das ein Formular enthält, welches wiederum Buttons enthält
                   */
                  function start() {
                  var listen2Click = document.getElementById("function_bar");
                  listen2Click.addEventListener("click", switchClass, false);
                  listen2Click.setAttribute("class", "js");
                  }
                  

                  Gibt es auch ein aside function_foo? – scnr ;-)

                  Nein, es ist der Container für die Steuerung der Angebote, quasi die funktionierende Theke, also die Funktionsbar. :-)

                  Es ist meistens die beste Wahl mit classList zu arbeiten, da hierbei nicht das Risiko besteht, dass ein Wert unbeabsichtigt überschrieben wird.

                  Ich habe mir getAttribute, setAttribute und removeAttribute aus der (alten) Doku herausgesucht und benutzt. Zudem sind die Namen selbsterklärend. Da ich seltenst mit JavaScript arbeite, ist das für mich tatsächlich relevant. Ich will ja auch, wie in diesem Fall tatsächlich zutreffend, nach mehreren Jahren erkennen können, was ich da zusammengestöpselt habe.

                  Allerdings ist classList mit add und remove mindestens genauso gut lesbar.

                  function inArray(item, array)
                  

                  Wenn es darum geht herauszufinden, ob ein bestimmter Wert in einem Array enthalten ist, dann gäbe es zu diesem Zweck auch in JavaScript eine eingebaute Methode, nämlich Array.prototype.includes.

                  Das war mir nicht bekannt. Ich suchte halt das Pendant zur PHP-Funktion und fand das obige, seinen Zweck erfüllende Beispiel.

                  function switchClass(e) {
                  if (!e) e = window.event;
                  

                  In einem Browser der mit dem Ereignismodell des DOM nichts anfangen kann, würde diese Funktion niemals aufgerufen werden. Die Prüfung ob ein Event-Objekt übergeben wurde kann man sich also sparen.

                  Das kommt davon, wenn man das zusammenkopiert …

                  Zumal du … konsequenterweise als Alternative noch e.srcElement hättest anbieten müssen. ;-)

                  Da der Code eh nur im Firefox und evtl. noch im Chromium funktionieren muss, sollte das kein Thema sein.

                  … wie auch immer, im Folgenden nochmal alles kompakt zusammengefasst.

                  window.addEventListener('DOMContentLoaded', function ( ) {
                  
                    const aside = document.getElementById('function_bar');
                  
                    aside.addEventListener('click', function (event) {
                      const value = event.target.value,
                            list = ['without_rework', 'with_rework', 'deletions'];
                  
                      document.body.className = list.includes(value) ? value : '';
                    });
                  
                  });
                  

                  Sieht grundsätzlich übersichtlicher aus, auch wenn ich das Konzept anonymer Funktionen immer noch etwas verwirrend finde. Zwei Fragen stellen sich mir dennoch.

                  1. Warum aside als Konstante und nicht als Variable?
                  2. Hinterlässt document.body.className = list.includes(value) ? value : ''; bei nicht zutreffender Bedingung nicht unnötigerweise ein leeres Class-Attribut?

                  Tschö, Auge

                  --
                  Wir hören immer wieder, dass Regierungscomputer gehackt wurden. Ich denke, man sollte die Sicherheit seiner Daten nicht Regierungen anvertrauen.
                  Jan Koum, Mitgründer von WhatsApp, im Heise.de-Interview
                  1. Hi,

                    • registriere den Event-Listener für das aside #function_bar,

                    Gibt es auch ein aside function_foo? – scnr ;-)

                    Nein, es ist der Container für die Steuerung der Angebote, quasi die funktionierende Theke, also die Funktionsbar. :-)

                    apropos Funktionsbar: Ist euch schon mal aufgefallen, dass heutzutage fast alles irgendwie "Funktion" haben muss?

                    Neulich ist mir die große Fassadenwerbung eines neuen Fitness-Centers in der Nähe aufgefallen, auf der angepriesen wird, was der Laden alles bietet. Neben den üblichen Trainings- und Fitnessangeboten, Sauna und so war auch "Functional Area" genannt. Ich habe nicht verstanden, was das wohl sein mag.

                    Und interessant ist auch der Bekleidungssektor: Da gibt es heute Funktionsjacken, Funktionsshirts, Funktionshosen und sogar Funktionsschuhe. Was muss ich mir unter Funktionsschuhen vorstellen? Laufen die vielleicht von selbst? Oder haben die einen eingebauten Kat zur Fußschweiß-Regeneration?

                    Oder ist Funktion einfach nur ein Buzzword, das die Marketingbranche gierig aufschnappt?

                    So long,
                     Martin

                    --
                    Bei der Umsetzung von guten Ideen hapert es meist viel mehr an der Wolle als an der Könne.
                    1. Hallo

                      Neulich ist mir die große Fassadenwerbung eines neuen Fitness-Centers in der Nähe aufgefallen, auf der angepriesen wird, was der Laden alles bietet. Neben den üblichen Trainings- und Fitnessangeboten, Sauna und so war auch "Functional Area" genannt. Ich habe nicht verstanden, was das wohl sein mag.

                      Da ja gerne mal Dinge, die dich nicht im mindesten interessieren, spurlos an dir vorbei gehen, sei dir gesagt, dass dort, also im „Functional Area“ jene Geräte stehen, die tatsächlich funktionieren. Was auch sonst‽

                      Und interessant ist auch der Bekleidungssektor: Da gibt es heute Funktionsjacken, Funktionsshirts, Funktionshosen und sogar Funktionsschuhe. …

                      Oder ist Funktion einfach nur ein Buzzword, das die Marketingbranche gierig aufschnappt?

                      Na aber sicher doch. Die Funktionen, mit denen die obenen benannten Kleidungsstücke beworben werden, beschränken sich ja typischerweise auf Funktionen, die der wohl meist mitgeführte Taschenrechner mit eingebauter Mobiltelefonfunktion eh schon bereitstellt. Anders als als Buzzword-Bullshit kann man das wohl nicht bezeichnen.

                      „Hier, Ihre neue Jacke mit ['Schrittzähler', 'Pulsmesser', 'GPS-Tracker', 'SchießMichTot']!“
                      „Aber das habe ich doch schon alles im Telefon?“
                      „Ja, das können Sie aber nicht anziehen!!!“

                      Tschö, Auge

                      --
                      Wir hören immer wieder, dass Regierungscomputer gehackt wurden. Ich denke, man sollte die Sicherheit seiner Daten nicht Regierungen anvertrauen.
                      Jan Koum, Mitgründer von WhatsApp, im Heise.de-Interview
                      1. Hi,

                        Neben den üblichen Trainings- und Fitnessangeboten, Sauna und so war auch "Functional Area" genannt. Ich habe nicht verstanden, was das wohl sein mag.

                        Da ja gerne mal Dinge, die dich nicht im mindesten interessieren, spurlos an dir vorbei gehen, sei dir gesagt, dass dort, also im „Functional Area“ jene Geräte stehen, die tatsächlich funktionieren. Was auch sonst‽

                        das war auch mein erster Gedanke. Aber da Geräte wie Stepper, Laufbänder etc. alle noch separat aufgezählt wurden, erschien mir das nicht plausibel.

                        Oder ist Funktion einfach nur ein Buzzword, das die Marketingbranche gierig aufschnappt?

                        Na aber sicher doch. Die Funktionen, mit denen die obenen benannten Kleidungsstücke beworben werden, beschränken sich ja typischerweise auf Funktionen, die der wohl meist mitgeführte Taschenrechner mit eingebauter Mobiltelefonfunktion eh schon bereitstellt.

                        Soweit ich das gesehen habe, geht es da eher um praktische Eigenschaften, bei der "Funktionsjacke" etwa viele Taschen, per Reißverschluss abtrennbare Ärmel, ein Hi-Tech-Isolierstoff und so, aber weniger um "Funktion" im technischen Sinn. Aber man braucht halt einen prägnanten, knackigen Begriff.

                        „Hier, Ihre neue Jacke mit ['Schrittzähler', 'Pulsmesser', 'GPS-Tracker', 'SchießMichTot']!“
                        „Aber das habe ich doch schon alles im Telefon?“
                        „Ja, das können Sie aber nicht anziehen!!!“

                        ;-)

                        So long,
                         Martin

                        --
                        Bei der Umsetzung von guten Ideen hapert es meist viel mehr an der Wolle als an der Könne.
                        1. Hallo

                          Neben den üblichen Trainings- und Fitnessangeboten, Sauna und so war auch "Functional Area" genannt. Ich habe nicht verstanden, was das wohl sein mag.

                          Da ja gerne mal Dinge, die dich nicht im mindesten interessieren, spurlos an dir vorbei gehen, sei dir gesagt, dass dort, also im „Functional Area“ jene Geräte stehen, die tatsächlich funktionieren. Was auch sonst‽

                          das war auch mein erster Gedanke. Aber da Geräte wie Stepper, Laufbänder etc. alle noch separat aufgezählt wurden, erschien mir das nicht plausibel.

                          Keiner hat gesagt, dass sie funktionieren, wenn sie woanders stehen. ;-)

                          Die Funktionen, mit denen die obenen benannten Kleidungsstücke beworben werden, beschränken sich ja typischerweise auf Funktionen, die der wohl meist mitgeführte Taschenrechner mit eingebauter Mobiltelefonfunktion eh schon bereitstellt.

                          Soweit ich das gesehen habe, geht es da eher um praktische Eigenschaften, bei der "Funktionsjacke" etwa viele Taschen, per Reißverschluss abtrennbare Ärmel, ein Hi-Tech-Isolierstoff und so, aber weniger um "Funktion" im technischen Sinn. Aber man braucht halt einen prägnanten, knackigen Begriff.

                          Naja, … z.B. abtrennbare Ärmel oder Hosentaschen gab es schon Jahrzehnte vor der „Erfindung“ des Begriffs „Funktionskleidung“.

                          Heutzutage werden aber tatsächlich Chips in die Kleidung eingenäht, um Funktionen zu ermöglichen, die sonst die Mitnahme zusätzlicher Geräte erforderten. Dass man das Smartphone oder (der neue abklingende Hype) die Smartwatch, die die Funktionen schon haben, fast immer bei sich trägt, ist verkaufstechnisch unerheblich.

                          Wer unbedingt will, soll seine Redundanz in Funktionen und Akkuladebedarf haben, auch wenn vermutlich das Erste meist unnötig und das Zweite meist unnötig lästig sein wird.

                          Tschö, Auge

                          --
                          Wir hören immer wieder, dass Regierungscomputer gehackt wurden. Ich denke, man sollte die Sicherheit seiner Daten nicht Regierungen anvertrauen.
                          Jan Koum, Mitgründer von WhatsApp, im Heise.de-Interview
                          1. Hi,

                            Soweit ich das gesehen habe, geht es da eher um praktische Eigenschaften, bei der "Funktionsjacke" etwa viele Taschen, per Reißverschluss abtrennbare Ärmel, ein Hi-Tech-Isolierstoff und so, aber weniger um "Funktion" im technischen Sinn. Aber man braucht halt einen prägnanten, knackigen Begriff.

                            Naja, … z.B. abtrennbare Ärmel oder Hosentaschen gab es schon Jahrzehnte vor der „Erfindung“ des Begriffs „Funktionskleidung“.

                            ja, natürlich. Aber man hat halt mal wieder einen neuen Begriff geprägt, um dem oberflächlichen Kunden diese Selbstverständlichkeiten wieder schmackhaft zu machen. Das ist ja nichts Neues - in der Werbung werden oft tolle Neuerungen dargestellt, und wenn man dann darüber nachdenkt, fällt einem auf, dass $konkurrenzprodukt das schon vor zehn Jahren hatte oder konnte.

                            Heutzutage werden aber tatsächlich Chips in die Kleidung eingenäht, ...

                            Das ist mir bekannt, war aber bei den "Funktions"-Textilien, die mir bisher aufgefallen sind, nicht der Fall - zumindest nicht äußerlich oder der Beschreibung nach erkennbar.

                            Wer unbedingt will, soll seine Redundanz in Funktionen und Akkuladebedarf haben, auch wenn vermutlich das Erste meist unnötig und das Zweite meist unnötig lästig sein wird.

                            Wieso Akku? Es gibt doch sogar schon Handtaschen mit flexiblen Solarzellen! Und bestimmt kann man die auch in die Rückenpartie des Sport-Shirts einarbeiten, um damit Schritt- und Pulszähler zu versorgen.

                            Ciao,
                             Martin

                            --
                            Bei der Umsetzung von guten Ideen hapert es meist viel mehr an der Wolle als an der Könne.
                    2. Hallo,

                      apropos Funktionsbar: Ist euch schon mal aufgefallen, dass heutzutage fast alles irgendwie "Funktion" haben muss?

                      Beispielsweise atmungsaktive Kleidung, d.h. Kleidung, die aktiv atmet. Das ist dann eine pneumatische Funktion.

                      Gruß
                      Kalk

                      1. Hi,

                        apropos Funktionsbar: Ist euch schon mal aufgefallen, dass heutzutage fast alles irgendwie "Funktion" haben muss?

                        Beispielsweise atmungsaktive Kleidung, d.h. Kleidung, die aktiv atmet. Das ist dann eine pneumatische Funktion.

                        ja, so würde das einen Sinn ergeben. Aber gibt es das? Meint man das wirklich, wenn man von "atmungsaktiv" redet? Ich dachte bisher, damit meint man bloß, dass die Klamotten den natürlichen Luftaustausch so wenig wie möglich behindern.

                        Andererseits werden die Entwickler von Textilien und Schuhen ja durchaus vor Herausforderungen gestellt. Durchlässigkeit für Feuchtigkeit zum Beispiel: Die vom Körper produzierte Feuchte (Schweiß) soll zwar nach außen gelangen, Feuchtigkeit von außen (Regen, Dunst) aber nicht nach innen. Ist für mich als Laien zunächst mal ein Widerspruch.

                        So long,
                         Martin

                        --
                        Bei der Umsetzung von guten Ideen hapert es meist viel mehr an der Wolle als an der Könne.
                    3. Hallo,

                      Und interessant ist auch der Bekleidungssektor: Da gibt es heute Funktionsjacken, Funktionsshirts, Funktionshosen und sogar Funktionsschuhe. Was muss ich mir unter Funktionsschuhen vorstellen? Laufen die vielleicht von selbst? Oder haben die einen eingebauten Kat zur Fußschweiß-Regeneration?

                      zufällig heute mittag beim Einkaufen im örtlichen Supermarkt wieder gesehen: Funktionsschuhe, das Paar für 17.99EU$. Neugierig habe ich mir die mal genauer angesehen. Die sahen aus wie leichte Sneaker, mit einer billig wirkenden, relativ steifen Plastiksohle und obenrum aus irgendeinem Textil-Synthetikzeug. Machten einen bequemen, wenn auch nicht unbedingt langlebigen Eindruck, und regentauglich wohl auch nicht, durch das komische Obermaterial hätte man vermutlich schnell nasse Füße.
                      Nur von "Funktion" konnte ich nichts entdecken.

                      Ganz ähnliche Schuhe hat Aldi letztes Jahr mal angeboten, und ich habe zugegriffen. Dort waren sie aber als "Walking-Schuhe" bezeichnet und hatten eine angenehm flexible Sohle, die auch ein sanftes Abrollen beim Laufen erlaubt.
                      Leider war schon nach rund 500km (geschätzt) die Sohle so abgenutzt, dass ich die Schuhe wegschmeißen konnte. Aber superbequem waren sie ...

                      Oder ist Funktion einfach nur ein Buzzword, das die Marketingbranche gierig aufschnappt?

                      Ich bin immer mehr davon überzeugt.

                      So long,
                       Martin

                      --
                      Bei der Umsetzung von guten Ideen hapert es meist viel mehr an der Wolle als an der Könne.
                      1. Hallo Martin,

                        Oder ist Funktion einfach nur ein Buzzword, das die Marketingbranche gierig aufschnappt?

                        Ich bin immer mehr davon überzeugt.

                        bei der Funktion handelt es sich genau genommen um eine Transferfunktion. Sie transferiert dein Geld in die Kasse des Händlers.

                        Gruß
                        Jürgen

                        1. Hi,

                          Oder ist Funktion einfach nur ein Buzzword, das die Marketingbranche gierig aufschnappt?

                          Ich bin immer mehr davon überzeugt.

                          bei der Funktion handelt es sich genau genommen um eine Transferfunktion. Sie transferiert dein Geld in die Kasse des Händlers.

                          ah, jetzt verstehe ich das so langsam! :-)
                          Dann ist es also nur eine Frage der Zeit, bis wir auch Funktionszeitschriften, Funktionsbier und Funktionspizza kaufen konnen. Äh, dürfen. Oder müssen?

                          Ciao,
                           Martin

                          --
                          Nein, dein Geld ist nicht weg. Es hat jetzt nur jemand anders.
                          1. Hallo Martin,

                            … Äh, dürfen. Oder müssen?

                            du kannst dich natürlich in Konsumverzicht üben, aber dann greift die Funktionsbank.

                            Gruß
                            Jürgen

                            1. n'Abend,

                              … Äh, dürfen. Oder müssen?

                              du kannst dich natürlich in Konsumverzicht üben, aber dann greift die Funktionsbank.

                              na klar, und zwar in meine Funktionstaschen.

                              Ciao,
                               Martin

                              --
                              Bei der Umsetzung von guten Ideen hapert es meist viel mehr an der Wolle als an der Könne.
                  2. Hallo Auge

                    Wenn es darum geht herauszufinden, ob ein bestimmter Wert in einem Array enthalten ist, dann gäbe es zu diesem Zweck auch in JavaScript eine eingebaute Methode, nämlich Array.prototype.includes.

                    Das war mir nicht bekannt. Ich suchte halt das Pendant zur PHP-Funktion und fand das obige, seinen Zweck erfüllende Beispiel.

                    Allerdings fehlt in deiner übersetzten Variante der PHP-Funktion namens in_array ein auch in JavaScript nicht unwesentliches Detail, nämlich die Möglichkeit, durch Übergabe eines Arguments für den optionalen dritten Parameter statt auf lenient equality auf strict equality zu testen. ;-)

                    Aber auch ohne die Verwendung von Array.prototype.includes, das ja tatsächlich noch nicht so lange Teil des (living) Standards ist, hätten dir einige etablierte Methoden für Arrayinstanzen zur Verfügung gestanden um das Ziel zu erreichen, wie zum Beispiel Array.prototype.some.

                    const array = ['tick', 'trick', 'track'];
                    
                    // arrow function
                    console.info(array.some(value => value == 'trick')); // true
                    
                    // ordinary function expression
                    const result = array.some(function (value) {
                      return value == 'donald';
                    });
                    
                    console.info(result); // false
                    

                    Diese Arraymethode erwartet als erstes Argument eine Rückruffunktion, die für jedes Element des Arrays aufgerufen wird, solange die Funktion keinen truthy value zurückgibt.

                    Gibt die Funktion bei einem Aufruf einen solchen Wert zurück, wird die Ausführung der Methode beendet und es wird true zurückgegeben. Gibt die Funktion hingegen für alle Elemente des Arrays einen falsy value zurück, dann ist der Rückgabewert der Methode entsprechend false. Damit ließe sich der Test ob ein Wert in dem Array enthalten ist also auch durchführen.

                    Ebenfalls beliebt ist die Variante mit Array.prototype.indexOf. Diese Methode prüft mit dem strict equality Vergleichsalgorithmus, ob der als erstes Argument an die Methode übergebene Wert in dem Array enthalten ist und gibt dann den Index der ersten Fundstelle zurück, oder, wenn kein passender Eintrag gefunden wurde, den Wert -1.

                    const array = ['garfield', 'odie'];
                    
                    if (array.indexOf('garfield')) {
                      console.log(true); //
                    }
                    
                    console.log(array.indexOf('garfield') != -1); // true
                    

                    Dabei muss aber natürlich berücksichtigt werden, dass der gesuchte Eintrag wie in dem Beispiel oben auch den Index 0 haben kann, bei dem es sich um einen falsy value handelt. Statt explizit auf -1 zu prüfen, kann hier aber auch der bitweise NOT Operator verwendet werden (Tilde), der wenn es sich bei dem Operanden um den Wert -1 handelt, 0 zurückgibt.

                    if (!~array.indexOf('garfield')) {
                      console.log(true); // true
                    }
                    

                    Da du in deinem Beispielcode das Ergebnis der Prüfung auch gleich verwenden willst, wenn denn der Wert in dem Array gefunden wurde, könnte man hier auch Array.prototype.find verwenden. Die Methode funktioniert ähnlich wie some, jedoch wird hier bei einem positiven Rückgabewert der als Argument übergebenen Funktion von der Methode nicht true zurückgegeben, sondern der Wert selbst.

                    const array = ['asterix', 'obelix'], name = 'asterix';
                    
                    // arrow function
                    console.log(array.find(value => value == name)); // asterix
                    
                    // ordinary function expression
                    const result = array.find(function (value) {
                      return value == 'idefix';
                    });
                    
                    console.log(result || ''); //
                    

                    Wird von der Rückruffunktion bei keinem Aufruf ein truthy value zurückgegeben, dann ist undefined der Rückgabewert der Methode. Allerdings finde ich die Variante mit includes hier nach wie vor am besten, auch wenn sie noch nicht flächendeckend implementiert ist. ;-)

                    Sieht grundsätzlich übersichtlicher aus, auch wenn ich das Konzept anonymer Funktionen immer noch etwas verwirrend finde.

                    Hmm. Wenn du etwas genauer beschrieben hättest, was genau du daran verwirrend findest, könnte ich dir bei der Entwirrung vielleicht besser helfen. So kann ich nur ein paar allgemeine Erklärungen zum Thema anbieten …

                    Fangen wir also damit an, dass du zunächst einmal zwei Möglichkeiten hast, wie du eine Funktion definieren kannst, nämlich entweder indem du die Funktion deklarierst (Function Declaration), oder aber indem du die Funktion als einen Ausdruck notierst, der wenn er ausgewertet wurde als Ergebnis eine Funktion zurückgibt (Function Expression).

                    // function declaration
                    function tintin ( ) {
                      return 'et milou';
                    }
                    

                    Betrachten wir also erstmal Funktionsdeklarationen, die so wie in dem Beispiel oben notiert werden. Hier ist klar, dass eine Notierung ohne Bezeichner nicht besonders sinnvoll wäre, da die Funktion dann nicht referenziert werden könnte. Entsprechend produziert eine anonyme Funktionsdeklaration, von einer hier nicht relevanten Ausnahme abgesehen (Export Default Declaration), immer einen Syntaxfehler.

                    Jedenfalls wird bei einer deklarierten Funktion der angegebene Funktionsbezeichner, hier also tintin, automatisch zur lexikalischen Umgebung des Ausführungskontextes hinzugefügt, in welchem die Funktion deklariert wurde, sodass sie über ihren Bezeichner referenziert werden kann.

                    Aber das ist nicht alles, denn deklarierte Funktionen werden darüber hinaus gehoistet, sprich sie werden so behandelt, als wären sie am Anfang des jeweiligen Gültigkeitsbereichs notiert worden, noch vor allen Anweisungen die da gegebenenfalls noch folgen. Darum können sie im Code aufgerufen werden bevor sie deklariert wurden.

                    console.log(milou( )); // et tintin
                    
                    function milou ( ) {
                      return 'et tintin';
                    }
                    

                    Wie gesehen ist das aber nicht die einzige Möglichkeit eine Funktion zu definieren, sondern die Definition kann auch innerhalb eines Ausdrucks erfolgen. Die Syntax für einen Funktionsausdruck ist dabei nicht anders als die einer Funktionsdeklaration, das heißt, die Unterscheidung kann immer nur mit Blick auf die Umgebung getroffen werden, in der die Funktion definiert wurde.

                    // named function expression
                    var homer = function simpson ( ) {
                      return 'jay';
                    };
                    

                    In diesem Beispiel haben wir eine Variablendeklaration, bei der die Variable mit einem benannten Funktionsausdruck initialisiert wird. Im Vergleich zu einer Funktionsdeklaration gibt es hier nun zwei wesentliche Unterschiede. So wird der angegebene Bezeichner der Funktion nicht der lexikalischen Umgebung des laufenden Ausführungskontextes hinzugefügt, sondern er kann nur innerhalb des Ausdrucks, also innerhalb des Körpers der Funktion angesprochen werden. Das heißt, die Funktion kann hier nur über die Variable referenziert werden der sie zugewiesen wurde.

                    var barney = function gumble ( ) {
                      if (typeof gumble == 'function') {
                        console.log('duff');
                      }
                    };
                    
                    barney( ); // duff
                    
                    gumble( ); // Reference Error - gumble is not defined
                    

                    Darüber hinaus wird die Funktion auch nicht gehoistet, sie kann also erst referenziert werden, nachdem die Variable initialisiert wurde. Genauer gesagt: Zwar wird die mit var deklarierte Variable hier ebenfalls bei der Initialisierung des Ausführungskontextes der lexikalischen Umgebung hinzugefügt, aber sie bleibt solange undefined bis ihr ein Wert zugwiesen wird, hier also das Ergebnis des Funktionsausdrucks.

                    Da es sich bei Funktionen in JavaScript um Bürger erster Klasse handelt, kann ein Funktionsausdruck überall notiert werden wo ein Ausdruck notiert werden darf, also zum Beispiel auch bei der Übergabe von Argumenten an eine andere Funktion. Oder auch als Rückgabewert einer Funktion.

                    window.addEventListener('DOMContentLoaded', function init ( ) {
                      console.log(typeof init); // function
                    });
                    
                    function produce ( ) {
                      return function product ( ) {
                        // do something
                      };
                    }
                    
                    console.log(typeof produce( )); // function
                    

                    Da nun der Bezeichner einer als Ausdruck notierten Funktion grundsätzlich nicht außerhalb der Funktion selbst sichtbar ist, kann er auch weggelassen werden. Darin liegt auch kein Nachteil, denn selbst wenn es beispielsweise für Debuggingzwecke unter Umständen sinnvoll sein kann einen Bezeichner anzugeben, ist die Referenzierbarkeit über einen eigenen Bezeichner für die Erfüllung einer Aufgabe meist keine Notwendigkeit.

                    // property
                    const object = {
                      lucky : function ( ) {
                        return 'eddie';
                      }
                    };
                    
                    console.log(object.lucky( )); // eddie
                    
                    const array = [1, 2, 3];
                    
                    // argument
                    array.forEach(function (value) {
                      console.log(value + 2); // 3, 4, 5
                    });
                    

                    Das heißt, oft trägt eine deklarierte Funktion lediglich zur Bevölkerung der lexikalischen Umgebung bei, obwohl sie nur an einer einzigen Stelle aufgerufen wird. Wobei zu berücksichtigen ist, dass eine deklarierte Funktion anders als ein Funktionsausdruck nicht unmittelbar aufgerufen werden darf.

                    // lexical environment binds handler
                    function handler (event) {
                      console.log(event.target.tagName);
                    }
                    
                    document.body.addEventListener('click', handler);
                    
                    // no binding here
                    document.body.addEventListener('click', function handler (event) {
                      console.log(event.target.tagName);
                    });
                    

                    Wird also wie hier im ersten Beispiel bei der Argumentübergabe an addEventListener nur eine Referenz auf eine zuvor deklarierte Funktion übergeben, dann sollte innerhalb der lexikalischen Umgebung dieses Ausführungskontextes besser keine andere Funktion oder Variable mit diesem Bezeichner deklariert werden.

                    Wird hingegen wie im zweiten Beispiel ein Ausdruck verwendet, dann kann es hier zu keinen Konflikten kommen. Und da die Funktion darüber hinaus ohnehin darauf angelegt ist, automatisch beim Ereigniseintritt aufgerufen zu werden und weil dafür kein Bezeichner nötig ist, könnte man die Funktion hier auch als anonymen Ausdruck notieren.

                    window.addEventListener('DOMContentLoaded', function ( ) {
                      // do something
                    });
                    

                    Für die Lesbarkeit beziehungsweise Verständlichkeit des Codes ist das nicht zwingend ein Nachteil denke ich, eher im Gegenteil, denn auf diese Weise ist eine Zusammenhängende Anweisung nicht über mehrere Stellen innerhalb des Quelltextes verstreut.

                    Noch einen Schritt weiter in diese Richtung gehen übrigens Pfeilfunktionen (Arrow Functions), wie ich sie in einigen der Beispiele weiter oben bereits verwendet habe. Denn diese Funktionen sind grundsätzlich anonym und sie können entsprechend nur als Ausdruck notiert werden.

                    const log = value => console.log(value);
                    
                    log('message'); // message
                    
                    const math = {
                      add : (a, b) => a + b
                    };
                    
                    log(math.add(4, 4)); // 8
                    

                    Neben anderen Vorteilen, wie etwa einer lexikalischen Bindung der Kontextvariable this, trägt gerade die kompakte Syntax ohne das Schlüsselwort function und ohne Funktionsbezeichner dazu bei, dass Implementierungen mittels Pfeilfunktionen in der Regel deutlich eleganter sind als vergleichbare Konstrukte mit gewöhnlichen Funktionen.

                    const array = ['foo', 'bar', 'baz'];
                    
                    // anonymous function expression
                    array.forEach(function (value) {
                      console.log(value);
                    });
                    
                    // function declaration
                    function print (value) {
                      console.log(value);
                    }
                    
                    array.forEach(print);
                    
                    // arrow function
                    array.forEach(value => console.log(value));
                    

                    Hinsichtlich des Debuggings ist Anonymität auch nicht unbedingt ein Problem, da Funktionsobjekte in der Regel über eine Eigenschaft mit dem Bezeichner name verfügen, für die bei unbenannten Funktionen implizit der Name der Variable oder der Eigenschaft hinterlegt wird, welcher sie zugewiesen wurden, und die von vielen Entwicklungsumgebungen examiniert wird.


                    Naja, wie auch immer. Ich hoffe anonyme Funktionen verwirren dich nun etwas weniger. ;-)

                    Viele Grüße,

                    Orlok

                  3. Hallo @Auge

                    Zwei Fragen stellen sich mir dennoch.

                    Sorry, dass die Antworten auf diese Fragen so lange auf sich haben warten lassen. ;-)

                    Aber zunächst muss ich noch eine kleine Korrektur meiner ersten Antwort vornehmen, denn da habe ich in einem Beispiel zur Verwendung der Methode Array.prototype.indexOf leider einen Fehler eingebaut:

                    const array = ['garfield', 'odie'];
                    
                    // if (!~array.indexOf('garfield')) {
                    
                    if (~array.indexOf('garfield')) {
                      console.log(true); // true
                    }
                    

                    Der logische vor dem binären NOT Operator ist hier natürlich Unsinn, da die Ausgabe ja nicht erfolgen soll wenn der Wert nicht in dem Array enthalten ist, sondern wenn er enthalten ist. :-P

                    Warum aside als Konstante und nicht als Variable?

                    Also du meinst, warum ich für aside nicht var verwendet habe? Oder weshalb ich nicht statt const eine Variable mit let angelegt habe? Oder einfach ganz allgemein?

                    Naja, wenn man den konkreten Fall isoliert betrachtet, dann wäre es egal gewesen, auf welche Weise man den Wert hinterlegt. Man hätte sich hier eine entsprechende Deklaration auch komplett sparen können, zumal die Referenz auf das Elementobjekt ja nur an einer Stelle gebraucht wird.


                    Jedenfalls, kurz gesagt, habe ich hier const verwendet, weil ich const immer dann verwende, wenn kein anderer Wert an den ausgewählten Bezeichner gebunden werden soll, also die Bindung von Bezeichner und Wert konstant bleibt. ;-)


                    Allerdings wäre es vielleicht ganz hilfreich, einmal die wesentlichsten Unterschiede zwischen den verschiedenen Variablentypen zu beschreiben, um meine Entscheidung besser nachvollziehen zu können.

                    Scope

                    Dabei wäre zunächst mal auf den Gültigkeitsbereich (Scope) von Variablen einzugehen. Denn hier besteht ein wesentlicher Unterschied zwischen solchen Variablen die mit var deklariert werden und solchen, die mittels let oder const in die Welt gesetzt werden.

                    // global environment
                    var number = 16;
                    
                    function test (condition) {
                      // function environment
                      if (condition) {
                        var number = 32;
                      }
                      console.log(number); // 32
                    }
                    
                    test(true);
                    
                    console.log(number); // 16
                    

                    Variablen die mittels var deklariert werden sind in Bezug auf ihre Sichtbarkeit mit dem jeweiligen Ausführungskontext (Execution Context) verknüpft. Sie sind also grundsätzlich an die lexikalische Umgebung eines Scripts, eines Moduls oder einer Funktion gebunden.

                    Mit Blick auf das Beispiel oben heißt das, dass die innerhalb der globalen Umgebung deklarierte Variable mit dem Bezeichner number im gesamten Programm sichtbar ist, und dass die innerhalb der Funktion test deklarierte Variable überall innerhalb dieser Funktion Gültigkeit besitzt.

                    // global environment
                    let number = 16;
                    
                    function test (condition) {
                      // function environment
                      if (condition) {
                        // block environment
                        let number = 32;
                      }
                      console.log(number); // 16
                    }
                    
                    test(true);
                    
                    console.log(number); // 16
                    

                    Bei let und const sieht das Ganze hingegen ein wenig anders aus, wie das beinahe identische Beispiel oben zeigt, denn anders als bei var-Variablen wird hier auch durch einen Block ein Gültigkeitsbereich definiert (Block Scope), weshalb die innerhalb des Anweisungsblocks der if-Anweisung notierte Deklaration der Variable number keine Auswirkungen auf den Rest des Funktionskörpers von test hat, sodass hier schließlich der Wert der globalen Variablen number in die Konsole geschrieben wird.

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

                    Das heißt, die Definition eines neuen Gültigkeitsbereichs bei var ist nur durch Einschluss der Deklaration in eine Funktion möglich, weshalb vor der Standardisierung von let und const oft unmittelbar aufgerufene Funktionsausdrücke (IIFE) zu diesem Zweck verwendet wurden, also eine Syntax wie bei der Funktion test in dem Beispiel oben. Mit let und const ist es hingegen möglich, im selben Ausführungskontext eine Kette von Gültigkeitsbereichen zu implementieren.

                    Darüber hinaus ist Block Scope aber nicht der einzige Unterschied hinsichtlich der Sichtbarkeit der Variablen, wie das folgende Beispiel zeigt:

                    function test (condition) {
                      for (let index = 0; index < 3; index ++) {
                        const value = 'message';
                        if (condition) {
                          console.info(value); // 3x message
                        }
                      }
                      console.info(index); // Reference Error - index is not defined
                    }
                    
                    test(true);
                    

                    Die im Anweisungsblock der Schleife deklarierte Konstante besitzt wie gesehen nur Gültigkeit innerhalb dieses Blocks, das heißt, sie wird bei jeder Iteration neu erzeugt und ist außerhalb des Blocks nicht sichtbar. So weit, so klar. Aber auch die mittels let im Schleifenkopf deklarierte Variable ist in ihrer Sichtbarkeit auf die Schleife beschränkt, weshalb der Versuch ihren Wert auszugeben hier einen Reference Error erzeugt.

                    const captains = new Map([
                      ['Kirk', 'James Tiberius'],
                      ['Picard', 'Jean-Luc']
                    ]);
                    
                    for (let entry of captains) {
                      console.info(entry.reverse( ).join(' ')); // James Tiberius Kirk, Jean-Luc Picard
                    }
                    
                    console.info(entry); // Reference Error - entry is not defined
                    

                    Wie hier zu sehen ist gilt das nicht nur für gewöhnliche for-Schleifen, sondern ebenso für andere Schleifentypen. Das bedeutet, mittels let oder const deklarierte Variablen sind außerhalb der Schleife grundsätzlich nicht sichtbar.

                    Bei Variablen die mit dem Schlüsselwort var deklariert wurden verhält es sich bekanntermaßen anders. Bezogen auf das folgende Beispiel können die Variablen index und value auch außerhalb der Schleife referenziert werden.

                    for (var index = 1700; index < 1701; index += 1) {
                      var value = 'Enterprise';
                    }
                    
                    console.info(index); // 1701
                    
                    console.info(value); // Enterprise
                    

                    Es ist also festzuhalten, dass const und let im Vergleich zu var eine leichtere Kontrolle hinsichtlich ihrer Sichtbarkeit ermöglichen. Wenn man davon ausgeht dass Variablen prinzipiell so lokal wie möglich angelegt werden sollten, dann besitzen let und const hier also einen Vorteil gegenüber Variablen die mit var deklariert werden.

                    Hoisting / Temporal Dead Zones

                    Wie ich in meiner ersten Antwort bereits erwähnte, werden var-Variablen ebenso wie Funktionen die deklariert wurden gehoistet, also bei der Initialisierung des jeweiligen Ausführungskontextes an den Anfang des ausführbaren Codes gezogen, wobei der Variable zunächst der Wert undefined zugewiesen wird.

                    // global environment
                    var word = 'foo';
                    
                    function test (condition) {
                      // function environment
                      console.info(word); // undefined
                      if (condition) {
                        var word = 'bar';
                      }
                    }
                    
                    test(false);
                    

                    Da var-Variablen immer Funktionsweit sichtbar sind bedeutet das, dass selbst wenn wie in dem Beispiel oben der Anweisungsblock des Conditional Statements nie betreten wird, die innerhalb der Funktion deklarierte Variable die gleichnamige Variable der äußeren lexikalischen Umgebung verschattet.

                    Das heißt, wann immer irgendwo innerhalb ihres Gültigkeitsbereichs eine Variable mit var deklariert wird, erfolgt die Erzeugung (und die Initialisierung mit undefined) der Variable bereits vor der Ausführung irgendwelcher Anweisungen in dem jeweiligen Codeabschnitt, lediglich die Zuweisung des Wertes (Assignment) erfolgt erst an der Stelle im Code an der sie notiert wurde.

                    Entsprechend wird beim Zugriff auf eine var-Variable vor ihrer Deklaration im Code auch keine Ausnahme geworfen, weder im Sloppy Mode noch im Strict Mode. – Anders als bei dem Versuch, eine mittels const oder let angelegte Variable vor ihrer Deklaration im Code zu referenzieren, denn hier wird unabhängig vom Ausführungsmodus des Programms grundsätzlich eine Fehler produziert.

                    function test ( ) {
                      try {
                        console.info(foo);
                      } catch (exception) {
                        console.error(exception); // Reference Error
                      }
                      let foo = 5;
                    }
                    
                    test( );
                    
                    console.info(bar); // Reference Error
                    
                    const bar = 3;
                    

                    Zwar findet auch hier die Bindung von Bezeichner und lexikalischer Umgebung des jeweiligen Abschnitts statt, bevor in diesem Abschnitt notierte Anweisungen ausgeführt werden, aber die Variablen werden dabei nicht initialisiert, sondern befinden sich zunächst in einem Zustand der inoffiziell als Temporal Dead Zone bezeichnet wird. Sie sind also für die Zeit bis zu ihrer tatsächlichen Deklaration im Code nicht referenzierbar.

                    function test ( ) {
                      let foo = 1;
                      if (true) {
                        // temporal dead zone start
                        console.log(foo); // Reference Error
                        // temporal dead zone end
                        let foo = 3;
                      }
                    }
                    
                    test( );
                    

                    Dass die Bindung bereits beim Eintritt in den jeweiligen Gültigkeitsbereich erfolgt zeigt das Beispiel oben. Sprich, es wird nicht etwa die gleichnamige Variable des äußeren Kontextes referenziert, sondern es wird, da die lexikalische Umgebung des Anweisungsblocks über eine Bindung für den Bezeichner foo verfügt, eine Ausnahme geworfen.

                    function outer ( ) {
                      // nested function
                      function inner ( ) {
                        console.info(foo); // bar
                      }
                      // declaration
                      const foo = 'bar';
                      // call
                      inner( );
                    }
                    
                    outer( );
                    

                    Wie hier zu sehen ist, handelt es sich dabei tatsächlich um eine Temporal Dead Zone, denn entscheidend ist nicht der Ort der Notierung (man beachte, dass inner hier deklariert und mithin ohnehin gehoistet wird), sondern der zeitliche Ablauf des Programmflusses, weshalb die Notierung von inner vor der Deklaration der Konstante unproblematisch ist.

                    Da die Verwendung von Variablen vor ihrer Deklaration ohnehin als schlechte Praxis anzusehen ist, weil hierbei immer das Risiko besteht, dass die spätere Deklaration vergessen wird, und der Code darüber hinaus auch schlechter lesbar ist, kann man wohl sagen, dass const und let aufgrund ihrer strictness in dieser Hinsicht eher geeignet sind einen guten Programmierstil zu fördern, als var es ist.

                    Aber wie dem auch sei, ist an dieser Stelle noch auf eine weitere Besonderheit in Zusammenhang mit der Temporal Dead Zone von const- und let-deklarierten Variablen hinzuweisen, welche bei der Verwendung des Operators typeof zu beobachten ist.


                    Aber dazu kommen wir erst im nächsten Teil der Antwort, da dieser Beitrag kurz davor ist die Zeichenbegrenzung zu sprengen und ich nicht mitten im Satz abbrechen will. ;-)

                    Also: Fortsetzung folgt!

                    1. Fortsetzung folgt!

                      Die angesprochene Besonderheit in Zusammenhang mit dem Operator typeof zeigt sich wenn versucht wird, den Typ des Wertes einer erst zu einem späteren Zeitpunkt mittels const oder let deklarierten Variable zu bestimmen, wenn sich die Variable also in der Temporal Dead Zone befindet. Erinnern wir uns aber zunächst daran, was passiert wenn wir das Gleiche bei einer mit var deklarierten Variable versuchen.

                      console.info(typeof Worf); // undefined
                      
                      var Worf = 'Klingon';
                      

                      Da mittels var deklarierte Variablen gehoistet werden, sie also erzeugt und mit dem Wert undefined initialisiert werden, bevor die Ausführung des mit dem jeweiligen Kontext assoziierten Codes beginnt, wird hier vom Operator typeof natürlich undefined zurückgegeben. Soweit keine Überraschung. ;-)

                      Nun sehen wir uns an was passiert, wenn wir mit dem Operator typeof versuchen den Wert einer Variable zu bestimmen, die überhaupt nicht deklariert wurde:

                      console.info(typeof Riker); // undefined
                      

                      Auch hier wird vom Operator typeof standardgemäß der String 'undefined' zurückgegeben.

                      Es wäre also zu erwarten, dass die Prüfung des Wertes einer noch nicht im Code deklarierten const- oder let-Variable ebenfalls den Typbezeichner undefined zurückgibt …

                      function Enterprise ( ) {
                        // TDZ start
                        console.info(typeof Data); // Reference Error
                        // TDZ end
                        let Data = 'Android';
                      }
                      
                      Enterprise( );
                      

                      … aber wie das Beispiel oben zeigt, fliegt uns statt dessen unser Programm mit einem Reference Error um die Ohren! – Also, was ist hier los? ;-)

                      Um zu verstehen was hier passiert, müssen wir uns zunächst einmal die Semantik des Operators typeof näher ansehen, beziehungsweise genauer gesagt, was passiert wenn es sich bei dem Operanden, also dem Ausdruck auf der rechten Seite, um eine Referenz handelt.

                      // global environment
                      
                      (function outer ( ) {
                        // function environment
                      
                        (function inner ( ) {
                          // function environment
                          console.info(typeof LaForge); // undefined
                        }( ));
                      
                      }( ));
                      

                      Handelt es sich wie in dem Beispiel hier bei dem Operanden von typeof um eine Referenz, dann wird natürlich versucht diese aufzulösen. Das heißt, es wird als erstes in der nächsten lexikalischen Umgebung nachgesehen, ob diese über eine Bindung für den gesuchten Bezeichner verfügt. Das wäre hier also die lexikalische Umgebung, die mit dem Ausführungskontext der Funktion mit dem Bezeichner inner assoziiert ist.

                      Da diese lexikalische Umgebung zwar über keine Bindung für den gesuchten Bezeichner verfügt, aber dafür über eine Referenz auf die lexikalische Umgebung des äußeren Kontextes, wird entsprechend dort weitergesucht. Ebenfalls erfolglos. Da schließlich auch in der globalen Umgebung keine Variable oder Funktion mit dem Bezeichner LaForge deklariert wurde, handelt es sich hier also um eine nicht auflösbare Referenz (Unresolvable Reference). Und für diesen Fall ist standardmäßig vorgesehen, dass von typeof der Wert 'undefined' zurückgegeben wird.

                      Jetzt haben wir aber schon im letzten Teil der Antwort festgestellt, dass Variablen, die mittels const oder let deklariert wurden, zwar nicht wie var-Variablen gehoistet werden, in dem Sinne, dass sie mit einem (Default-)Wert initialisiert werden, aber dass sie eben dennoch vor dem Eintritt in den jeweiligen Scope an die dazugehörige lexikalische Umgebung gebunden werden.

                      Das heißt, bezogen auf das Ursprungsbeispiel mit Data handelt es sich bei dem Operanden von typeof nicht um eine unauflösbare Referenz, denn eine Bindung für diesen Bezeichner in der lexikalischen Umgebung der Funktion Enterprise besteht ja. Es ist eben nur nicht möglich auf die Variable zuzugreifen, da diese nicht Initialisiert wurde. – Deswegen: Reference Error.

                      Redeclaration

                      Ein weiterer Unterschied zwischen solchen Variablen die mittels var deklariert werden und solchen die mittels const oder let deklariert werden besteht im Hinblick auf das Verhalten, das sich zeigt wenn im gleichen Gültigkeitsbereich für den selben Bezeichner mehr als eine Deklaration vorgenommen wird.

                      var number = 64;
                      console.log(number); // 64
                      
                      var number = 128;
                      console.log(number); // 128
                      

                      Bei var-Variablen passiert hier nichts, außer dass bei einer weiteren Deklaration, so denn dabei wie in dem Beispiel ein Wert zugewiesen wird, der alte Wert überschrieben wird. Es wird also bei der Evaluierung des jeweiligen Ausführungskontextes in diesem Fall kein Fehler erzeugt, sondern eben schlicht eine Variablenbindung hinterlegt, es wird also so getan, als wäre die zweite Deklaration nur eine Referenz oder ein Zuweisungsausdruck.

                      // Type Error before execution
                      let word = 'foo';
                      
                      let word = 'foo';
                      

                      Das sieht bei let und freilich auch bei const anders aus. Hier wird sowohl im schlampigen also auch im strikten Ausführungsmodus grundsätzlich eine Ausnahme geworfen.

                      // Type Error before execution
                      function foo (bar) {
                        let bar = 12;
                      }
                      

                      Dabei spielt es auch keine Rolle, ob wie in dem Beispiel oben der gleiche Bezeichner verwendet wird wie bei einem formalen Parameter, oder ob im gleichen Gültigkeitsbereich eine Variable mit einem anderen Typ existiert, oder ob dort eine Funktion mit dem entsprechenden Bezeichner deklariert wurde. Eine Redeklaration von const- und let-Variablen produziert immer einen Fehler.

                      Da die mehrfache Verwendung eines Bezeichners für verschiedene Variablen oder Funktionen innerhalb des selben Gültigkeitsbereichs wohl praktisch immer auf eine Nachlässigkeit des Programmierers zurückzuführen ist, ist dieses Verhalten auch durchaus begrüßenswert.

                      Passiert so etwas mit einer var-Variablen, dann wird wie gesehen keine Ausnahme geworfen, und die Fehlersuche kann sich unter Umständen als schwierig erweisen, sofern man keine Entwicklungsumgebung verwendet die smart genug ist die Mehrfachdeklaration anzuzeigen.


                      Zusammenfassend lässt sich also sagen, dass const und let im Vergleich zu var die Befolgung weit strikterer Regeln einfordern, selbst wenn das Programm nicht im im Strict Mode ausgeführt wird, das heißt, durch ihre Verwendung kann eine ganze Reihe potentiell fehlerträchtiger Praktiken von vorneherein ausgeschlossen werden, weshalb ich empfehlen würde, grundsätzlich let und const zu verwenden.

                      Wann nun aber let und wann const? ;-)

                      Naja, der Sinn einer Konstante liegt im Wesentlichen darin, dass es aufgrund der für die gesamte Laufzeit des Programms (beziehungsweise Lebenszeit der Variablen) festgelegte Bindung von Bezeichner und Wert für den Interpreter möglich wird, bestimmte Optimierungen durchzuführen, um die Performanz des Programms zu verbessern.

                      Wenn also ein Wert hinterlegt werden soll und klar ist, dass die Variable diesen Wert behalten soll, dann verwende ich const. Ist es hingegen beabsichtigt, dass die Variable zu einem späteren Zeitpunkt einen anderen Wert zugewiesen bekommt, dann verwende ich let.

                      const object = {
                        print ( ) {
                          console.info(this.value);
                        }
                      };
                      
                      object.value = 42;
                      
                      object.print( ); // 42
                      

                      Schließlich handelt es sich bei der Verwendung von const auch um keine große Einschränkung, denn konstant ist hier tatsächlich nur die Bindung von Bezeichner und Wert, nicht aber der Wert selbst. Das heißt, wenn ein Objekt (und damit auch eine Funktion oder ein Array) als Wert einer Konstante hinterlegt wird, dann kann dieses nach wie vor verändert werden. Auch wenn dadurch vermutlich die Versuche zur Optimierung des Programms durch den Interpreter torpediert werden. ;-)

                      Hinterlässt document.body.className = list.includes(value) ? value : ''; bei nicht zutreffender Bedingung nicht unnötigerweise ein leeres Class-Attribut?

                      Das tut es. Aber du hattest die Änderungen ja nicht von der Präsenz des class-Attributes auf body abhängig gemacht, sondern von dessen Wert, weshalb es hier wohl ziemlich egal ist, ob das Attribut gesetzt bleibt oder nicht. Sonst kann man es aber natürlich mittels removeAttribute entfernen.

                      Viele Grüße,

                      Orlok

                    2. Hallo

                      Zwei Fragen stellen sich mir dennoch.

                      Sorry, dass die Antworten auf diese Fragen so lange auf sich haben warten lassen. ;-)

                      Meine Fresse! Deine Antworten sind wieder einmal mehrere eigene Wiki-Artikel. Überflogen habe ich's schon mal, besonders die Beispiele zu den Kontexten der verschiedenartigen Deklarationen und deren Erklärungen. Bis in sämtliche Ecken durchdrungen habe ich das aber noch nicht. :-)

                      Warum aside als Konstante und nicht als Variable?

                      Also du meinst, warum ich für aside nicht var verwendet habe?

                      Ja, mir stellte sich die Frage, warum du statt des für mich gängigen var const verwendet hast.

                      Jedenfalls, kurz gesagt, habe ich hier const verwendet, weil ich const immer dann verwende, wenn kein anderer Wert an den ausgewählten Bezeichner gebunden werden soll, also die Bindung von Bezeichner und Wert konstant bleibt. ;-)

                      Aha.

                      (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.

                      Deswegen war ich auch so verwundert, dass du const statt var für die Deklaration einer „stinknormalen“ Variable verwendetest.

                      Hoisting / Temporal Dead Zones

                      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.

                      Tschö, Auge

                      --
                      Wir hören immer wieder, dass Regierungscomputer gehackt wurden. Ich denke, man sollte die Sicherheit seiner Daten nicht Regierungen anvertrauen.
                      Jan Koum, Mitgründer von WhatsApp, im Heise.de-Interview
                      1. 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

                        1. Hallo

                          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.

                          Zumindest ist es hier so detailliert, dass es bei mir Verwirrung stiftete.

                          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.

                          … soweit ich das beurteilen kann, haben Konstanten in PHP und JavaScript, von der Syntax einmal abgesehen, nicht viele Gemeinsamkeiten.

                          Offensichtlich mehr oder minder. Hat eine Konstante in PHP einen Wert, hat sie ihn unveränderlich bis zum Ende der Ausführung des Skripts. Soweit stimmen die Konztepte überein. Allerdings lässt sich – zumindest gilt das für dien klassische Methode, also nicht die klassenbezugene Deklaration in einem Namespace – eine Konstante in PHP nicht redeklarieren, was gemäß deiner Beispiele in JavaScript möglich ist.

                          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 erneute Deklarieren der Konstante hat mich nicht so sehr verwundert. Es war eher das Konzept, einen grundsätzlich veränderlichen Wert in eine Konstante zu packen, wobei ich von PHPs Konzept der Konstante als global erreichbarem Bezeichner/Wert ausgegangen bin [1]. Das hat ja nicht nur den Vorteil der Erreichbarkeit von überall, sondern auch den Nachteil der Erreichbarkeit von überall. Der eingeschränkte Gültigkeitsbereich der Funktion war mir ja nicht bewusst. Zudem gilt die Verwendung von Konstanten für solchen Fitzelkram™ in PHP in vielen Situationen als mit Kanonen auf Spatzen geschossen. Und da fragte ich mich eben, warum du denn nicht einfach eine Variable benutztest.

                          [Exception bei Mehrfachdeklaration im selben Kontext]

                          Das … gilt … 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.

                          Hmm, so unterschiedlich scheinen die Konzepte doch nicht zu sein. Denn das Gleiche gilt in PHP für global deklarierte Konstanten als auch für die Mehrfachdeklaration innerhalb eines Namensraums.

                          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 der geneigte Leser beachten mag, dass ein Array als Wert einer Konstante erst ab/bei PHP7 möglich sind.

                          Tschö, Auge

                          --
                          Wir hören immer wieder, dass Regierungscomputer gehackt wurden. Ich denke, man sollte die Sicherheit seiner Daten nicht Regierungen anvertrauen.
                          Jan Koum, Mitgründer von WhatsApp, im Heise.de-Interview

                          1. Ich meine die klassische Definition der Konstante abseits der Definition innerhalb des Namensraums einer Klasse. ↩︎

    2. @@Blumentopf

      Im Allgemeinen ist es nicht die beste Idee, alle Sprachvarianten auf eine Seite zu packen und nur jeweils eine davon anzuzeigen. Unnütz übertragene Daten.

      Bezüglich der Frage, ob es sinnvoll ist, beide verwendeten Sprachen in einem Dokument unterzubringen, möchte ich ergänzen, dass die Seite nur sehr wenig Text enthält, und ich es daher für effiezienter halte, das alles einzubinden, als Seiten neu zu laden.

      In deinem speziellen Fall kann das aber durchaus der gangbare Weg sein.

      Bleibt aber dennoch die Frage: warum? Warum sollten Nutzer die Sprache umschalten wollen, wenn sie die Seite von vornherein in ihrer bevorzugten Sprache angezeigt bekommen? (d.h. in der Sprache, die ihr Browser als ihre bevorzugte angibt) Denn das sollten sie.

      Die Ressouce sollte also schon vom Server mit einer Markierung ausgeliefert werden, welche Sprache die für den jeweiligen Nutzer die (vermeintlich) passende ist. Bspw. <html lang="de"> vs. <html lang="en">. Die jeweils passende Sprache ermittelt ein serverseitiges Script anhand des Accept-Language-Headers bzw. eines evtl. gesetzten Cookies (wobei dieser dann Vorrang hat).

      Sollte die automatisch ermittelte Sprache nicht die gewünschte sein, kann der Nutzer umschalten. Dabei könnte per JavaScript das lang-Attribut des html-Elements geändert werden und ein Cookie gesetzt bzw. überschrieben werden. (Den Nutzer fragen, ob er das will?) Durch das geänderte lang-Attribut greifen andere Selektoren und die Sichtbarkeit von Textbereichen wird entsprechend umgeschaltet.

      Probleme dabei:

      1. Die Umschaltung müsste assistiven Technologien per ARIA-Attributen mitgeteilt werden, damit auch Screenreader-Nutzer in den Genuss der Sprachumschaltung kommen.

      2. Ohne JavaScript geht die Sprachumschaltung nicht. Lässt sich so lösen, dass man die Ressource nochmals vom Server holt – mit einem Parameter ?lang=… im URI, der Vorrang vor Cookie und Accept-Language-Header hat.

      LLAP 🖖

      --
      “You might believe there are benefits for the developer, but first of all, you should put those behind the interest of the user.” —Stefan Tilkov
      Selfcode: sh:) fo:} ch:? rl:) br:> n4:& va:| de:> zu:} fl:{ ss:| ls:# js:|
      1. @@Gunnar Bittersmann

        Die Ressouce sollte also schon vom Server mit einer Markierung ausgeliefert werden, welche Sprache die für den jeweiligen Nutzer die (vermeintlich) passende ist. Bspw. <html lang="de"> vs. <html lang="en">. Die jeweils passende Sprache ermittelt ein serverseitiges Script anhand des Accept-Language-Headers bzw. eines evtl. gesetzten Cookies (wobei dieser dann Vorrang hat).

        Warum ein serverseitiges?

        Weil es AFAIK keine Möglichkeit gibt, mit JavaScript an den Accept-Language-Header zu kommen.

        LLAP 🖖

        --
        “You might believe there are benefits for the developer, but first of all, you should put those behind the interest of the user.” —Stefan Tilkov
        Selfcode: sh:) fo:} ch:? rl:) br:> n4:& va:| de:> zu:} fl:{ ss:| ls:# js:|
      2. Hallo Gunnar, natürlich war mir von Anfang an klar, dass es die beste und eleganteste Lösung wäre, wenn der Nutzer von all dem nichts mitbekommt, und sich die Sprache automatisch gemäß seinen Vorlieben einstellt, wie man das ja auch von allen wichtigen Seiten so kennt.

        Nur habe ich nach etwas Recherche vor diesem Königsweg quasi kapituliert, da ich als Laie da nicht mehr durchsteige. Meine php Erfahrung beschränkt sich auf die einmalige Verwendung von server side includes.

        Ich habe also nach einer Möglichkeit gesucht, mit den mir halbwegs vertrauten Mitteln eine englische Version der Seite anzubieten. Wenn ich eine einfache und übersichtliche Anleitung finde für die php Lösung, werde ich vielleicht auch noch versuchen, das zu probieren.

        1. Hallo,

          Meine php Erfahrung beschränkt sich auf die einmalige Verwendung von server side includes.

          nur dass das mit PHP nichts zu tun hat, sondern wieder eine völlig andere Technologie ist.

          So long,
           Martin

          --
          Bei der Umsetzung von guten Ideen hapert es meist viel mehr an der Wolle als an der Könne.
          1. nur dass das mit PHP nichts zu tun hat, sondern wieder eine völlig andere Technologie ist.

            ..soviel zu meinen Kenntnissen.. ich meinte sowas in der Art: <?php include ..

            1. Hi,

              nur dass das mit PHP nichts zu tun hat, sondern wieder eine völlig andere Technologie ist.

              ..soviel zu meinen Kenntnissen..
              ich meinte sowas in der Art:
              <?php include ..

              ah, verstehe. Das ist natürlich PHP. Aber Server Side Includes (SSI) ist tatsächlich was anderes.

              So long,
               Martin

              --
              Bei der Umsetzung von guten Ideen hapert es meist viel mehr an der Wolle als an der Könne.
        2. Hallo Blumentopf,

          Ich habe also nach einer Möglichkeit gesucht, mit den mir halbwegs vertrauten Mitteln eine englische Version der Seite anzubieten.

          Mach zwei Seiten. (http://celsius-fahrenheit.net) Das ist zwar schlechter als language negotiation aber besser als das cookie-gefrickel. PHP kommt nur zum tragen um die aktuelle Seite nicht zu verlinken sowie bei der Zuordnung des Linkziels bei „diese Seite auf deutsch/this site in english“.

          Bis demnächst
          Matthias

          --
          Wenn eine Idee nicht zuerst absurd erscheint, taugt sie nichts. (Albert Einstein)
          1. Mach zwei Seiten.

            Der Vorteil von einer Seite war aus meiner Sicht, dass es dann einfacher ist, Dinge zu ändern, die nicht die Sprache betreffen.

            Bis ich eine Lösung mit automatischer Sprachwahl habe, werde ich wohl erst mal diese Fassung online stellen. Mein momentanes Hauptproblem mit den doppelten Cookies (siehe oben, weiß gerade nicht, wie man hier nen Anker wirft..) dürfte den durchschnittlichen Nutzer auch nicht betreffen, da es erst nach exzessivem Hin- und Herschalten auftritt.

            Um das Neuladen zu umgehen, werde ich wohl – da alle sagen, es müsste das auch ohne Neuladen aktualisieren – noch mal eine leere Testseite von Null auf aufbauen, um zu schauen, wo der Fehler liegt. Besten Dank allen und Grüße

            1. Hallo Blumentopf,

              weiß gerade nicht, wie man hier nen Anker wirft..

              Einfach einen Link zum gewünschten Beitrag setzen.

              Bis demnächst
              Matthias

              --
              Wenn eine Idee nicht zuerst absurd erscheint, taugt sie nichts. (Albert Einstein)
        3. @@Blumentopf

          natürlich war mir von Anfang an klar, dass es die beste und eleganteste Lösung wäre, wenn der Nutzer von all dem nichts mitbekommt, und sich die Sprache automatisch gemäß seinen Vorlieben einstellt, wie man das ja auch von allen wichtigen Seiten so kennt.

          Nur habe ich nach etwas Recherche vor diesem Königsweg quasi kapituliert, da ich als Laie da nicht mehr durchsteige. Meine php Erfahrung […]

          Für einfache Sprachvereinbarung (ohne Cookies) brauchst du keine PHP-Kenntnisse. Dafür genügt Apaches MultiViews.

          LLAP 🖖

          --
          “You might believe there are benefits for the developer, but first of all, you should put those behind the interest of the user.” —Stefan Tilkov
          Selfcode: sh:) fo:} ch:? rl:) br:> n4:& va:| de:> zu:} fl:{ ss:| ls:# js:|