Window Object
J o
- browser
- javascript
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
@@J o
EAlso suche ich weiter finde aber nicht unter welcher Eigenschaft ich die Methoden
foo
undbar
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 🖖
Hey,
Die Funktionen
foo()
undbar()
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
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
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
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
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
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
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
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:
self
verwenden für das globale Objektthis
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
Tach!
Zum einen: Das window object enthält sich selbst unter
window.self
und zusätzlich unterwindow.window
, dies lässt sich mindestens 5 mal fortsetzen alsowindow.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.