J o: Window Object

Einen wunderschönen Nachmittag zusammen,

Ich hätte da gern einmal Zwei Fragen zu dem window object.

Zum einen: Das window object enthält sich selbst unter window.self und zusätzlich unter window.window, dies lässt sich mindestens 5 mal fortsetzen also window.self.self.self.self.self. Warum enthält sich das Objekt selbst und dann auch noch doppelt, sowie in so vielen Ebenen?

Dies ist mir aufgefallen, da ich eine Funktion gesucht habe, die ich ausführen möchte, wobei ich nur dessen Name als String vorliegen habe. Dazu folgendes:

$(function(){
	function foo() {
		//Do something
	}
	function bar() {
		//Do something
	}

	window['bar']();
}
function foobar(){}

~~Jetzt ist mir im window object aufgefallen das window.foo existiert aber nicht window.bar. Schon dies allein verwirrt mich. ~~ Korrektur: window.foo sowie window.bar sind nicht existent. Alle Funktionen welche nicht in der ready Methode stehen, wie foobar(), sind ebenfalls alle im window objekt verfügbar. Also suche ich weiter finde aber nicht unter welcher Eigenschaft ich die Methoden foo und bar finde. Hätte da Jemand einen Tipp für mich?

Gruß
Jo

akzeptierte Antworten

  1. @@J o

    EAlso suche ich weiter finde aber nicht unter welcher Eigenschaft ich die Methoden foo und bar finde. Hätte da Jemand einen Tipp für mich?

    Die Funktionen foo() und bar() existieren nur innerhalb der Funktion, in der sie definiert wurden. Da diese anonym ist – viel Spaß bei der Suche …

    LLAP 🖖

    --
    „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
    1. Hey,

      Die Funktionen foo() und bar() existieren nur innerhalb der Funktion, in der sie definiert wurden. Da diese anonym ist – viel Spaß bei der Suche …

      Jep. Aber ich kann foo()/bar() auch nicht innerhalb der Funktion aufrufen, was das eigentliche Problem ist.

      Gruß
      Jo

      1. Hallo J o,

        da sie lokal sind und nicht auf dem window-Objekt als Eigenschaften angelegt werden, kann ein Aufruf mit window['bar']() auch nicht funktionieren.

        bar() würde klappen.

        Wenn Du ein namentliches Funktions-Verzeichnis brauchst, das innerhalb deines Ready-Handlers funktioniert, kannst Du zum Beispiel ein lokales Objekt mit Methoden anlegen. Es gibt eine Menge Möglichkeiten, wie man Methoden in ein Objekt bringt oder sie darauf aufruft.

        let bar = 'zap';
        let myFuncs = {       // var statt let, wenn Du ältere Browser unterstützen willst
           foo: function() {  alert('1'); },
           [bar]: function() { alert('2'); }     // Verwendet Inhalt von baz als Methodenname!
        };
        myFuncs['ook'] = function() { alert('banana'); };
        
        myFuncs.foo();        // funktioniert
        myFuncs['foo']();     // funktioniert auch
        myFuncs.bar();        // FUNKTIONIERT NICHT
        myFuncs.zap();        // funktioniert
        myFuncs['zap']();     // das natürlich auch
        myFuncs['ook'](); // Macht den Bibliothekar glücklich
        

        Aber - brauchst Du eins? Was genau ist dein Plan?

        Rolf

        --
        sumpsi - posui - clusi
        1. Hey,

          Ich habe den Funktionsnamen nur als String vorliegen.
          Ich habe gerade die ganze Funktion umgeschrieben zu :

          function ready() {
          
          	this.foo = function(){},
          	this.bar = function(){this.foo()},
            
          }
          
          

          Mit dem Versuch this['bar']() aber das geht natürlich auch nicht, hätte ich doch lieber erstmal mit einem Fiddle testen sollen.

          Gruß
          Jo

        2. Hey,

          let bar = 'zap';
          let myFuncs = {       // var statt let, wenn Du ältere Browser unterstützen willst
             foo: function() {  alert('1'); },
             [bar]: function() { alert('2'); }     // Verwendet Inhalt von baz als Methodenname!
          };
          myFuncs['ook'] = function() { alert('banana'); };
          
          myFuncs.foo();        // funktioniert
          myFuncs['foo']();     // funktioniert auch
          myFuncs.bar();        // FUNKTIONIERT NICHT
          myFuncs.zap();        // funktioniert
          myFuncs['zap']();     // das natürlich auch
          myFuncs['ook'](); // Macht den Bibliothekar glücklich
          

          Jup, gerade getestet :

          function ready() {
          
          	this.foo = function(){ console.log('hmz')}
          	this.bar = function(fun){this[fun]()}
            
          }
          
          var r = new ready();
          
          r.bar('foo')
          

          Gruß
          Jo

          1. Hey,

            Ja, kleiner Anfänger fehler...

            function ready() {
            
            	this.foo = function(){ console.log('hmz')}
            	this.bar = function(fun){this[fun]()}
              $('body').queue(function(){ this.bar('foo') }); //1
            	this.bar('foo')	//2
            }
            
            var r = new ready();
            
            

            Kann auch nicht funktionieren weil this (1) nicht this (2) ist.

            Gruß
            Jo

            1. Hallo J o,

              ja, mit this muss man aufpassen. Das ist das "aktuelle Kontext-Objekt", und welches das ist, ist manchmal nicht so ganz offensichtlich.

              Wenn man lokal Funktionsobjekte als Callback definiert, die auf das „äußere this“ zugreifen sollen - wie Du es ja gern gehabt hättest, findet man bei den meisten Leuten das Pattern, this an eine andere lokale Variable zuzuweisen und in den inneren Funktionen diese Variable zu verwenden. Häufig verwendete Namen dafür sind self, that oder _this; vermutlich gibt's auch mit Visual Basic sozialisierte Leute, die me verwenden 😀

              Rolf

              --
              sumpsi - posui - clusi
              1. Hey,

                ja, mit this muss man aufpassen. Das ist das "aktuelle Kontext-Objekt", und welches das ist, ist manchmal nicht so ganz offensichtlich.

                Passiert schon mal das man auf dem Schlauch steht.

                Aber die erste Frage interessiert mich doch schon noch. Hat da Jemand eine Antwort?

                Gruß
                Jo

  2. Hallo Jo,

    eine Frage ist noch offengeblieben: warum gibt's window.window und window.self. Ob sie BEIDE mit HTML 5 definiert wurden oder ob es einen davon auch schon früher gab (und vielleicht der eine Microsoft war und der andere Netscape), das kann ich Dir nicht mehr sagen. Eine Spec, die sie nennt, kenne ich erst ab HTML 5. Vorsicht beim Googeln - man findet sogar in Referenz-Werken wie Stackoverflow ganz oben und hochbepunktet Aussagen wie „das ist das selbe“. Nein. Ist es nicht.

    window.window sollte offensichtlich sein; Das Window-Objekt ist der Container für die globalen Variablen, und window ist eine globale Variable. Ganz einfach.

    D.h. eigentlich ist es nicht GANZ so einfach, aber wenn Du das wirklich wissen willst, guck unter WindowProxy in die Spec von HTML.

    window.self wird verständlich, wenn man neuere JavaScript-Techniken betrachtet. Zunächst mal: Das, was wir so locker "Klassen" nennen, sind in der HTML Spec zumeist INTERFACES. D.h. da ist irgendein Objekt, implementiert durch irgendeine tief-technische, umgebungsspezifische Klasse, aber es verspricht Dir: "Ich implementiere das Window-Interface, also kannst Du Dich darauf verlassen, dass ich alles tun kann, was ein Window tun können muss".

    Es gibt noch jemand anderen, der Dich so treuherzig anschaut, und das ist das WorkerGlobalScope Interface. Wenn Du einen WebWorker abspaltest, dann braucht der auch einen globalen Scope, und aus diversen Gründen ist das NICHT das Window-Objekt. Sondern etwas eigenes, eben ein WorkerGlobalScope. Beide - Window und WorkerGlobalScope - erben vom DOM-Interface EventTarget, und viele Dinge, die man bei der Kommunikation zwischen Vordergrund-Task und Worker-Tasks tut, basieren auf Messages und Events. Nun möchte man beim Programmieren der Infrastruktur dafür nicht alles zweimal schreiben, und jetzt kommt self ins Spiel. Es wäre echt irreführend, wenn ein WorkerGlobalScope sich selbst über eine globale Variable window referenzieren würde. self ist da deutlich klarer. „I bims, dein globaler Kontext“. Sowohl Window als auch WorkerGlobalScope enthalten self und stellen damit im Wesentlichen ihren kleinsten gemeinsamen Nenner bereit: das EventTarget. Es ist de facto noch etwas mehr, bei Interesse folge den Links zur Spec. Wenn Du nun Messaging zwischen deinen Threads programmierst, nimmst Du immer self.addEventListener statt window.addEventListener und alles ist gut.

    Lange Rede, kurzer Sinn: Wenn Du ohne WebWorker arbeitest, kannst Du window und self synonym verwenden.

    Setzt Du WebWorker ein, muss der im Worker ausgeführte Code self verwenden, um auf den globalen Kontext zuzugreifen. window gibt es dort nicht. D.h. du könntest abfragen if (self.window) { ... } um zu erkennen, ob dein Code im Window-Thread oder in einem Worker-Thread abgefragt wird.

    Es könnte also sinnvoll sein, sich folgendes anzugewöhnen:

    • immer self verwenden für das globale Objekt
    • wenn man eine Closure-fähige Kopie von this braucht, dafür NICHT self verwenden, sondern etwas anderes wie that oder me. Notiz an mich: Du hast im Büro ein Todo, Rolf!

    Rolf

    --
    sumpsi - posui - clusi
  3. Tach!

    Zum einen: Das window object enthält sich selbst unter window.self und zusätzlich unter window.window, dies lässt sich mindestens 5 mal fortsetzen also window.self.self.self.self.self. Warum enthält sich das Objekt selbst und dann auch noch doppelt, sowie in so vielen Ebenen?

    Zeig mal mit einem Finger auf dich selbst. Der Finger zeigt also auf dich, und du stehst da und hast einen Arm mit einer Hand und einem Finger dran, der auf dich zeigt. Der Finger zeigt also auf dich, und du stehst da und hast einen Arm mit einer Hand und einem Finger dran, der auf dich zeigt. Der Finger zeigt also auf dich, und du stehst da und hast einen Arm mit einer Hand und einem Finger dran, der auf dich zeigt. Der Finger zeigt also auf dich, und du stehst da und hast einen Arm mit einer Hand und einem Finger dran, der auf dich zeigt. Und so weiter, ein Ende gibts da nicht. Wenn du den Finger wegnimmst, geht der Verweis auf dich verloren (aber nicht du selbst).

    Das Window-Objekt ist jedenfalls der globale Scope. Und wenn man sich auf diesen beziehen möchte, muss man irgendwas haben, was man anfassen kann. Und das ist die Eigenschaft window, die auf das Window-Objekt zeigt. Gäbe es die nicht, könnte man nur irgendeineWindowEigenschaft = neuerWert schreiben und das klappt nicht aus lokalen Scopes heraus. Zudem zeigt this auch nur im globalen Scope auf window. Du müsstest dir also selbst einen Anfasser basteln, mit dem du gezielt auf den globalen Scope kommst. Mit der Eigenschaft window ist das bereits getan worden. window.irgendeineWindowEigenschaft = neuerWert greift auch aus lokalen Scopes auf den globalen Scope zu, jedenfalls solange window nicht lokal neu angelegt wurde.

    Allerdings gibt es auch andere Umgebungen, die nicht Window als globalen Kontext haben, wie beispielsweise serverseitiges Javascript oder Web Worker. Dort kann man mit self den globalen Scope referenzieren. Warum nun auch noch self und nicht window neben serversideGlobalScope und webWorkerGlobalScope? Funktionen müssen nicht unbedingt wissen oder herausfinden, in welcher Umgebung sie laufen. Und window wäre außerhalb vom Window-Objekt auch nicht richtig, also gibts das self, das in allen Umgebungen auf den globalen Scope zeigt. Damit hat man im Window-Objekt nun window und self, aber gut, ist eben historisch gewachsen.

    dedlfix.