Aber ok, jetzt ist es klar: Es wird also dann nicht automatisch das globale Objekt (window) als Container angenommmen und
!window.v
ausgewertet. So wäre es wäre doch eigentlich logisch.
Jein. In beiden Fällen wird die Variable letztlich am globalen Objekt gesucht. Der Unterschied lässt sich so erklären:
In beiden Fällen werden Referenzen erzeugt. Eine Referenz besteht vereinfacht gesagt aus einer Basis und einem Namen. Die Basis ist das »Objekt«, an dem nach dem Namen gesucht wird. Die Basis kann entweder direkt ein normales, der Programmierung zugängliches Objekt sein oder ein internes Objekt, der Environment Record eines Ausführungskontexts. Das kann man verallgemeinernd als Variablenobjekt bezeichnen.
Bei if (foo) ist der globale Ausführungskontext die Basis der Referenz. Letztlich wird wie gesagt am window-Objekt nach der Variable gesucht, denn das ist das Variablenobjekt für den obersten Kontext.
Bei if (window.foo) hingegen wird explizit das globale Objekt als Referenzbasis verwendet.
Das führt dann zu einer unterschiedlichen Verarbeitung der Referenzen. Die besagte interne GetValue-Funktion regelt das Auflösen von Referenzen:
»4. If IsPropertyReference(V), then
a) If HasPrimitiveBase(V) is false, then let get be the [[Get]] internal method of base, otherwise let get be the special [[Get]] internal method defined below.
b) Return the result of calling the get internal method using base as its this value, and passing GetReferencedName(V) for the argument.«
Wenn die Basis ein normales Object ist (oder ein Primitive, der dann vorher in ein Object umgewandelt wird), dann rufe dessen [[Get]]-Methode auf. Die gibt bei unbekannten Eigenschaften wie gesagt einfach undefined zurück.
»5. Else, base must be an environment record.
Return the result of calling the GetBindingValue (see 10.2.1) concrete method of base passing GetReferencedName(V) and IsStrictReference(V) as arguments.«
Wenn die Basis ein »Object Environment Record« ist – das ist der Fall, wenn Identifier im globalen Kontext aufgelöst werden –, so rufe GetBindingValue auf. Diese Methode ist nun pingelig; wenn kein entsprechendes Binding existiert, dann quittiert sie mit einem ReferenceError.
Mathias