I've been planning to check up on this and finally came
around doing it ;-)
So doing window['dwr'] felt like a decent fix,
however, and this is the strange bit, on IE:
window['dwr'] = {
};
dwr.wibble = 'x';
if (dwr == null) var dwr = {};
Ends
up re-defining dwr because (dwr == null) is true. I have no idea why, but
IE was broken because not all declarations of DWR did it in the same
way.
I've tried
but can't trigger this bug. Anything else I need to do?
If
you sync to a DWR from a week ago you should see engine.js use window['dwr']
and interface scripts use var dwr (IIRC), and IE detects dwr == null and then
goes on to re-declare
it.
I
found the source of this problem and it is because of an IE bug I haven't seen
before, combined with the current (of October 22) anatomy of DWR script files.
A
page using DWR normally includes engine.js and one or more interface scripts,
and all these files redefine dwr[.engine] whenever needed:
<script type='text/javascript' src='dwr/engine.js'>
if
(window['dwr'] == null) window['dwr'] =
{};
if
(dwr['engine'] == null) dwr['engine'] = {};
<script
type='text/javascript' src='dwr/interface/serviceObj.js'>
if (dwr == null) var dwr =
{};
if (dwr.engine == null) dwr.engine =
{};
Note that the
|dwr| object is handled as a window property in engine.js but as a global
variable (var) in the interface script. This is what triggers the IE bug, and
what happens is that when execution enters the second script element, IE
does this:
-
Registers all global variables declared in this
section (this is, and should, be done without considering true/false
conditions in if-branches).
-
Somehow IE misses that |dwr| has already been defined
and does what it usually does when declaring a new, previously
non-existing, variable: sets its value to
undefined.
-
After declaring variables (and compiling code) it is
time to execute global code. The "if (dwr == null)" will now be true and
the assignment "dwr = {}" will be
executed.
So the bug is triggered in step (2) when |dwr| has been
defined through a window property. It doesn't happen when a var-declaration is
used in the first script element, or when both script elements use the window
property.
It is quite easy to reproduce the problem. Just insert
the following two script elements in a page:
<script
type='text/javascript'>
window.myObj
= {};
alert(
myObj ); // It's defined here...
</script>
<script
type='text/javascript'>
alert(
myObj ); // ... but not here
if (myObj
== null) var myObj = {};
alert(
myObj ); // ... and here our
code has reassigned it
</script>
The new dojo inspired code using |this| doesn't trigger
the bug as it doesn't use a var-declaration in the interface
script:
<script type='text/javascript'
src='dwr/engine.js'>
if (typeof
this['dwr'] == 'undefined') { dwr = { };
}
<script
type='text/javascript'
src='dwr/interface/serviceObj.js'>
if (typeof this['dwr']
== 'undefined') this.dwr =
{};
So,
an easy way of avoiding the IE bug is to declare the |dwr| object in the same
way in all places (which is almost true now).
There is one additional factor that could be interesting: going back to
using a var-declaration (everywhere) would avoid the hard-to-find IE bug when an
HTML element is given an id of "dwr" and IE declares a corresponding JS
variable. This will not very often be a problem though, as engine.js is normally
included before any markup with ids so our |dwr| variable "will
win".
But my vote is still on using |window| instead of |this| for clarity
in this code ;-)
Best
regards
Mike