Access window.a
and a
when both are not defined generate distinct results because they are evaluated from distinct algorithms.
window.a
is evaluated for the reference value a
in the reference window
;
a
is evaluated using the reference value of a
;
Reference
First, we need to understand how Javascript references each object, which occurs through an interface called Reference
. An object Reference
is composed of three parts:
- The basic value;
- The name of the reference;
- A boolean flag that defines whether it is strict (Strict);
The base value of a reference may be undefined
, an object, a boolean, a string, a symbol, a number or a record of environment. When the base value is undefined
means that the object Reference
cannot be solved.
With that in mind, we need to define some procedures that will be necessary to understand the algorithm further.
Accessing the object a
Thus, when the code will be analyzed the object is identified a
internally a reference is defined (Reference
) for it and as it is an object that cannot be solved, the value base
will be as undefined
. When executing a code that requires the value of a
, just as console.log(a)
, the method will be executed GetValue(V)
of the reference following the algorithm:
ReturnIfAbrupt(V)
.
- If
Type(V)
is not Reference
, Return V
.
- Let
base
be GetBase(V)
.
- If
IsUnresolvableReference(V)
is true, throw a ReferenceError
Exception.
- If
IsPropertyReference(V)
is true, then
- If
HasPrimitiveBase(V)
is true, then
- Assert: In this case, base will Never be
undefined
or null
.
- Set base to
!ToObject(base)
.
- Return
?base.[[Get]](GetReferencedName(V), GetThisValue(V))
.
- Else,
- Assert:
base
is an Environment Record
.
- Return
?base.GetBindingValue(GetReferencedName(V), IsStrictReference(V))
.
In this case we have a baseline reference undefined
for the object a
, then in step 4, when the validation is done IsUnresolvableReference(V)
is returned true
and therefore launched the exception ReferenceError
.
Accessing the object window.a
Similar to when the object is directly accessed a
, so that the value of window.a
references will also be defined internally, one for the object window
and another for the object a
. To the object a
shall be a reference equal to the previous one, based on undefined
, but the difference lies in the existence of reference to the object window
which exists and can be resolved. Thus, different from the previous situation, in which the value of a
is assessed from GetValue(V)
, the value of window.a
will be evaluated from the function [[Get]](P, Receiver)
of the interface Object
, being P
the reference to the object a
and Receiver
the reference to the object window
. The algorithm executed for this will be:
- If
P
was Previously observed as a non-configurable, non-writable Own data Property of the target with value V
, then [[Get]]
must Return the SameValue
as V
.
- If
P
was Previously observed as a non-configurable Own accessor Property of the target Whose [[Get]]
attribute is undefined
, the [[Get]]
Operation must Return undefined
.
As the value P
will be the reference to the object a
, the basic value of which is undefined
, step 2 will be executed, causing [[Get]]
return undefined
.
Do window.a
is equal to a
?
No, as shown, the values will be evaluated differently and produce different results.
But why then window.a === a
is true?
Because when the variable is defined a reference to it is stored within the "global" object of the current scope. When defined in the overall scope of the application, this object will be the window
. When it is defined in a limited scope, this object will be another (and I do not know if it is accessible at runtime as is the window
).
To confirm this information just check the algorithm used when defining a variable by running PutValue(V, W)
:
ReturnIfAbrupt(V)
.
ReturnIfAbrupt(W)
.
- If
Type(V)
is not Reference
, throw a ReferenceError
Exception.
- Let
base
be GetBase(V)
.
- If
IsUnresolvableReference(V)
is true, then
- If
IsStrictReference(V)
is true, then
- Throw a
ReferenceError
Exception.
- Let
globalObj
be GetGlobalObject()
.
- Return
?Set(globalObj, GetReferencedName(V), W, false)
.
- Else if
IsPropertyReference(V)
is true, then
- If
HasPrimitiveBase(V)
is true, then
- Assert: In this case, base will Never be
undefined
or null
.
- Set base to
!ToObject(base)
.
- Let
succeeded
be ?base.[[Set]](GetReferencedName(V), W, GetThisValue(V))
.
- If
succeeded
is false and IsStrictReference(V)
is true, throw a TypeError
Exception.
- Return.
- Else,
- Assert:
base
is an Environment Record
.
- Return
?base.SetMutableBinding(GetReferencedName(V), W, IsStrictReference(V))
.
That basically, when it’s done var a = 1
, a reference to the object a
, initially at base value undefined
due to Hoisting.
Thus, running the algorithm, in step 5 IsUnresolvableReference(V)
return true and thus, not being a strict reference, seek the reference to the global object GetGlobalObject()
, which in this case, because it is a global variable will be the object window
, and the field shall be defined GetReferencedName(V)
with the value W
. So when it’s done var a
we will also have the value in window.a
(or window['a']
).
From this the reference of a
can be resolved and the next times there is an assignment to the object a
in the code step 6 will be executed, updating the value of it.
So var a = 1
is the same as doing window["a"] = 1
?
No, although it produces the same result. As we have seen, when evaluating the expression var a = 1
the operation will be carried out Set(window, "a", 1, false)
, however the value "a"
which will be the key in the object window
is evaluated from the reference to the object a
, through function GetReferencedName(V)
, while doing window["a"] = 1
this internal reference is not generated.
"Reading an undefined variable causes an error:" Ok, but the question is: every variable is a property of the window object, so actually calling it is calling by the window property, not?
– Máttheus Spoo
@Máttheusspoo yes, that’s what’s in my answer.
– Maniero
Not every variable is a property of the object
window
. I will edit the answer by stressing this.– Luiz Felipe