« Return to Thread: window. or this. prefix

RE: window. or this. prefix

by mikewse :: Rate this Message:

Reply to Author | View in Thread

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:
  1. Registers all global variables declared in this section (this is, and should, be done without considering true/false conditions in if-branches).
  2. 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.
  3. 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

 « Return to Thread: window. or this. prefix