weston said:
I'm still a bit confused. I do see that properly scoping the variable
as you're talking about fixes the problem. I just can't figure out for
the life of me why it being a global variable would prevent it from
receiving something via the assignment operator.
I will try to provide an explanation that I think of as the most
likely one. It is still a long shot, so corrections are welcome.
Undeclared variables and global variables become a property of the
Variable Object of the global execution context, that is, the
Global Object:
| 10.1.3 Variable Instantiation
|
| Every execution context has associated with it a variable object.
| Variables and functions declared in the source text are added as
| properties of the variable object. For function code, parameters
| are added as properties of the variable object.
|
| Which object is used as the variable object and what attributes
| are used for the properties depends on the type of code, but the
| remainder of the behaviour is generic. [...]
| 10.2.1 Global Code
| · The scope chain is created and initialised to contain the
| global object and no others.
| · Variable instantiation is performed using the global object as
| the variable object and using property attributes { DontDelete }.
| · The this value is the global object.
(Could someone please point me to where it is specified that undeclared
variables become properties of the Global Object, too, as implementations
do?)
However,
1. the Global Object appears to be the global Window object in the
Internet Explorer (IE) Application Object Model (AOM), which
includes the IE Document Object Model (DOM);
2. as Matt already roughly explained, in the IE AOM, ID'd (and named IIRC)
elements in the markup result in the creation of properties of the
global Window object that store a reference to the element DOM object
that represents the element, where the properties have the ID or name
of the respective element as their name -- in short, e.g.
<element id="foo" ...>
somewhere in the markup results in
// workaround: let _global be a reference to the Global Object
_global.foo = elementReference;
Now, if JScript as used in IE was a conforming implementation of
ECMAScript Edition 3 that implements ECMAScript regarding the simple
assignment operation to the letter, and let us assume from here that
it does, with
hometab = document.getElementById('hometab');
the following would take place:
| 11.13.1 Simple Assignment ( = )
|
| The production AssignmentExpression : LeftHandSideExpression =
| AssignmentExpression is evaluated as follows:
|
| 1. Evaluate LeftHandSideExpression.
| 2. Evaluate AssignmentExpression.
| 3. Call GetValue(Result(2)).
| 4. Call PutValue(Result(1), Result(3)).
| 5. Return Result(3).
where GetValue is defined as
| 8.7.1 GetValue (V)
|
| 1. If Type(V) is not Reference, return V.
| 2. Call GetBase(V).
| 3. If Result(2) is null, throw a ReferenceError exception.
| 4. Call the [[Get]] method of Result(2), passing GetPropertyName(V) for
| the property name.
| 5. Return Result(4).
and PutValue is defined as
| 8.7.2 PutValue (V, W)
|
| 1. If Type(V) is not Reference, throw a ReferenceError exception.
| 2. Call GetBase(V).
| 3. If Result(2) is null, go to step 6.
| 4. Call the [[Put]] method of Result(2), passing GetPropertyName(V) for
| the property name and W for the value.
| 5. Return.
| 6. Call the [[Put]] method for the global object, passing
| GetPropertyName(V) for the property name and W for the value.
| 7. Return.
The error message you get --
| Error: Object doesn't support this property or method. Code: 0.
-- is most certainly not related in retrieving the object reference with
document.getElementById() as you experience no problems with locally
declared variables or assignments to properties where there is no
respective element (object). So let us ignore GetValue here.
PutValue, however, is more interesting. In step 4 of 11.13.1, PutValue
is called where V is assigned _global.foo and W is assigned some value
(here: the reference to the element object you retrieved with
document.getElementById()), roughly speaking. Now,
| 1. If Type(V) is not Reference, throw a ReferenceError exception.
where Type is defined as
| 5.2 Algorithm Conventions
|
| [...] Type(x) is used as shorthand for "the type of x".
Type(V) is Reference, so no ReferenceError exception is thrown.
| 2. Call GetBase(V).
where GetBase is defined as
| 8.7 The Reference Type
| [...]
| GetBase(V). Returns the base object component of the reference V.
Meaning Result(2) would be _global.
| 3. If Result(2) is null, go to step 6.
Result(2) is not null, so we continue with the next step:
| 4. Call the [[Put]] method of Result(2), passing GetPropertyName(V) for
| the property name and W for the value.
Here is where the "magic" comes in. Keep in mind that _global [Result(2)]
is a reference to the Global Object and that we established before that the
Global Object is a Window _host object_ in the IE AOM.
[[Put]] is defined as follows:
| 8.6.2.2 [[Put]] (P, V)
|
| When the [[Put]] method of O is called with property P and value V, the
| following steps are taken:
|
| 1. Call the [[CanPut]] method of O with name P.
| 2. If Result(1) is false, return.
| 3. If O doesn't have a property with name P, go to step 6.
| 4. Set the value of the property to V. The attributes of the property
| are not changed.
| 5. Return.
| 6. Create a property with name P, set its value to V and give it empty
| attributes.
| 7. Return.
and [[CanPut]] as follows:
| 8.6.2.3 [[CanPut]] (P)
|
| The [[CanPut]] method is used only by the [[Put]] method.
| When the [[CanPut]] method of O is called with property P, the following
| steps are taken:
|
| 1. If O doesn't have a property with name P, go to step 4.
| 2. If the property has the ReadOnly attribute, return false.
| 3. Return true.
| 4. If the [[Prototype]] of O is null, return true.
| 5. Call the [[CanPut]] method of [[Prototype]] of O with property name P.
| 6. Return Result(5).
However,
| 8.6.2 Internal Properties and Methods
|
| Internal properties and methods are not part of the language. They are
| defined by this specification purely for expository purposes. An
| implementation of ECMAScript must behave as if it produced and operated
| upon internal properties in the manner described here. For the purposes
| of this document, the names of internal properties are enclosed in double
| square brackets [[ ]]. When an algorithm uses an internal property of an
| object and the object does not implement the indicated internal property,
| a TypeError exception is thrown.
| [...]
| For native objects the [[Get]], [[Put]], [[CanPut]], [[HasProperty]],
^^^^^^^^^^^^^^
| [[Delete]] and [[DefaultValue]] methods behave as described in described
| in sections 8.6.2.1, 8.6.2.2, 8.6.2.3, 8.6.2.4, 8.6.2.5 and 8.6.2.6,
| respectively, [...]. Host objects may implement these methods in any
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| manner unless specified otherwise; for example, one possibility is that
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| [[Get]] and [[Put]] for a particular host object indeed fetch and store
| property values but [[HasProperty]] always generates false.
Or is there some hidden magic here I"m not aware of...
There probably is.
HTH
PointedEars