window == document

G

Garrett Smith

I'm confused about IE's evaluation of window == document.

IE:
window == document; // true
document == window; // false

I came across this while testing to see if an object is a window.

I need this so that in the registry cleanup for DOM events, that if the
object is window, then don't unregister callbacks. This works fine as
callbacks for window don't need cleanup, but it is also important as
removing unload callbacks before they fire will mean those callbacks
won't fire ever -- that's bad.

So I want to continue the loop if the object is window, but came across
this oddity. I am going to base my programming strategy around the
operands being in a certain side of == -- and I really don't like doing
that -- then at the very least I need a comment explaining why. I can't
explain it because I don't understand it. Somebody please fix that.
 
T

Thomas 'PointedEars' Lahn

Garrett said:
I'm confused about IE's evaluation of window == document.

IE:
window == document; // true
document == window; // false

(I can confirm this for IE 6.0.2800.1106 / JScript 5.6.6626)

Well, those are references to host objects, and JScript is buggy there, too.
It works fine here (always `false') if you use `===' instead of `=='.


PointedEars
 
R

RobG

I'm confused about IE's evaluation of window == document.

IE:
window == document; // true
document == window; // false

Are you sure that *somewhere* in ECMA-262 it doesn't say that host
objects can change value depending on which side of an equality they
are on? Seems they have a get-out-of-jail-free card for every other
such circumstance.

If that was true, the spec was consistent and the same logic was
applied to identity and strict equality, would that help? ;-)
 
D

David Mark

I'm confused about IE's evaluation of window == document.

IE:
window == document; // true
document == window; // false

I came across this while testing to see if an object is a window.

I need this so that in the registry cleanup for DOM events, that if the
object is window, then don't unregister callbacks. This works fine as
callbacks for window don't need cleanup, but it is also important as
removing unload callbacks before they fire will mean those callbacks
won't fire ever -- that's bad.

Will you please put that Kool-aid down? You don't need such cleanup
if you avoid the circular references we have discussed here ad
nauseam.
So I want to continue the loop if the object is window, but came across
this oddity. I am going to base my programming strategy around the
operands being in a certain side of == -- and I really don't like doing
that -- then at the very least I need a comment explaining why. I can't
explain it because I don't understand it. Somebody please fix that.

No mystery. They are host objects, so they can do whatever they want.

You should change your design so that you do not have to differentiate
between windows and documents.
 
G

Garrett Smith

Stefan said:
I may be missing something, but don't you want both of these to evalute
to false? If so, Thomas's suggestion (using ===) should solve the
problem. If you're dealing with some weird edge case, a comment should
do it, IMHO. As if our code wasn't already riddled with "this is only
for IE compatibility" comments ;-)
The problem with === is that window === window is not always true.

javascript: alert([window === window.window, window === self])
I've never encountered this case, but I agree: it's definitely weird,
non-standard behavior. I wish there was a way to talk to the IE
developers, to ask them questions like this. With almost every other
browser, you could just look at the source code and see what's going on,
but IE is completely opaque. They don't even have a public bug tracker.

They do have a bug tracker (slow, when it works):
http://connect.microsoft.com/IE

I've filed bugs there myself.

Good bugs sometimes get marked as WONTFIX, INVALID, or Can't Reproduce.

The W3C Mailing Lists might seem like a way to talk to IE devs, but they
are a waste of time. The W3C is a pay-to-play organization arrogantly
out of control (put your money where your mouth is or STFU (or we'll ban
you permanently, lie about the reasons and lie and say it's only for two
weeks)).

My current test is based off using window on RHS. Given `a` and `b`, if
they are both the window, then
a == b.window; // true

If either `a` or `b` is `document`, then:
a == b.window; // false

In my code, there isn't any way `a` could be undefined because a
TypeError would prevent the object from being added to the registry:

a.addEventListener // <-- TypeError if a is undefined.

I mention undefined because Where the value on the LHS is undefined or
null and the value on the RHS does not have a window property.

var a;
a === [].window; // true, both are undefined.

But that can't happen in my code as it is now.
 
G

Garrett Smith

David said:
Will you please put that Kool-aid down? You don't need such cleanup
if you avoid the circular references we have discussed here ad
nauseam.

No worries, kid: I spare the Kool aid for girls like you. It's either
protein shakes, tea, or coffee.
No mystery. They are host objects, so they can do whatever they want.
Sure thing, they're host objects.

I'm trying to figure out this behavior in a particular case. You don't
seem to have the answer.
You should change your design so that you do not have to differentiate
between windows and documents.
Were you making comments about code you haven't read? Or is it about the
strategy mentioned in the (my) first paragraph of the OP?
 
A

Asen Bozhilov

Garrett said:
I'm confused about IE's evaluation of window == document.

IE:
window == document; // true
document == window; // false

There yet another bug, and you can see same behavior with others host
objects:

window.alert(window == new ActiveXObject('Microsoft.XMLHTTP')); //true
window.alert(new ActiveXObject('Microsoft.XMLHTTP') == window); //
false

window.alert(window == document.documentElement); //true
window.alert(document.documentElement == window); //false
 
G

Garrett Smith

Asen said:
There yet another bug, and you can see same behavior with others host
objects:

window.alert(window == new ActiveXObject('Microsoft.XMLHTTP')); //true
window.alert(new ActiveXObject('Microsoft.XMLHTTP') == window); //
false

window.alert(window == document.documentElement); //true
window.alert(document.documentElement == window); //false

Interesting.

It seems comparing window with elements in the document is true.

alert(window == document.body)
alert(window == document.links[0])
alert(window == document.body.firstChild)
alert(window == window.item);
alert(window == document.childNodes.item)
alert(window == document.getElementsByTagName("p")[0]);
alert(window == document.body.appendChild(document.createComment("")));
window == document.body.appendChild(document.createElement("div"))

All true, but window is not equal to element that is not in the document
or text node.

alert(window == document.createElement("div"))
alert(window == document.body.appendChild(document.createTextNode("")))

Both false.

We can take == one step further to other objects in IE:
alert( document.childNodes.item == document.body );

The `frames` object is also ==, when it is on the RHS:
alert(window == frames)

Some modern browsers, including IE, report true. Safari 2, Chrome 4,
BB9k all report false. Both browsers provide some sort of proprietary
collection there.

alert(window === frames);
IE, Op10, Chrome 4, Saf 2: false
FF, Saf 3+: true

Reversing the operands as `frames == window` has a different result, but
only in IE.
alert(frames == window);

IE: false

HTML 5 specifies:
"The window, frames, and self DOM attributes must all return the
Window object's browsing context's WindowProxy object."

http://www.w3.org/TR/html5/browsers.html#dom-window

I can sort of see the case for frames === window, if the objects have
identical properties (frames.document == window.document, etc).
 
G

Garrett Smith

Garrett said:
Asen said:
Garrett Smith wrote:
[...]

The `frames` object is also ==, when it is on the RHS:
alert(window == frames)

Some modern browsers, including IE, report true. Safari 2, Chrome 4,
BB9k all report false. Both browsers provide some sort of proprietary
collection there.
s/Both browsers/Those browsers
 
D

David Mark

Garrett said:
Interesting.

Not particularly. Host objects can do whatever they want.
It seems comparing window with elements in the document is true.

alert(window == document.body)
alert(window == document.links[0])
alert(window == document.body.firstChild)
alert(window == window.item);
alert(window == document.childNodes.item)
alert(window == document.getElementsByTagName("p")[0]);
alert(window == document.body.appendChild(document.createComment("")));
window == document.body.appendChild(document.createElement("div"))

All true, but window is not equal to element that is not in the document
or text node.

alert(window == document.createElement("div"))
alert(window == document.body.appendChild(document.createTextNode("")))

Both false.

All highly uninteresting. Just serves to show that you can't treat host
objects like they are native.
We can take == one step further to other objects in IE:
alert( document.childNodes.item == document.body );

The `frames` object is also ==, when it is on the RHS:
alert(window == frames)

Some modern browsers, including IE, report true. Safari 2, Chrome 4,
BB9k all report false. Both browsers provide some sort of proprietary
collection there.

They can do whatever they want (and you should avoid relying on the
results).
alert(window === frames);
IE, Op10, Chrome 4, Saf 2: false
FF, Saf 3+: true

Reversing the operands as `frames == window` has a different result, but
only in IE.
alert(frames == window);

IE: false

Fair enough. :)
HTML 5 specifies:
"The window, frames, and self DOM attributes must all return the
Window object's browsing context's WindowProxy object."

And what does that have to do with anything? The tested browsers are
not HTML5 implementations.
http://www.w3.org/TR/html5/browsers.html#dom-window

I can sort of see the case for frames === window, if the objects have
identical properties (frames.document == window.document, etc).

I can't see it, but they all have a case as they are implementation
dependant host objects. As long as you refrain from treating them like
natives, you'll be fine. ;)
 
M

Michael Haufe (\TNO\)

I'm confused about IE's evaluation of window == document.
[...]

A similar strange thing is the type evaluation in vbscript:

TypeName(window) -> HTMLWindow2
TypeName(document) -> HTMLDocument
VarType(window) -> vbObject
VarType(document) -> vbString
IsObject(window) -> True
IsObject(document) -> True

So maybe the HTMLDocument class is simply bugged?
 
G

Garrett Smith

Michael said:
I'm confused about IE's evaluation of window == document.
[...]

A similar strange thing is the type evaluation in vbscript:

TypeName(window) -> HTMLWindow2
TypeName(document) -> HTMLDocument
VarType(window) -> vbObject
VarType(document) -> vbString
IsObject(window) -> True
IsObject(document) -> True

So maybe the HTMLDocument class is simply bugged?
Possibly all nodes in the document have an internal type String.

If that is the case, then comparing two objects, where one is type
string, should result in string conversion.

window == "[object]"; // true
document == "[object]"; // true

However, document == window is false, so type conversion can only be
part of the reason.
 
G

Garrett Smith

kangax said:
I don't see how that could work, given that a window object might
originate from another frame or window (if you care about cross-window
or cross-frame interactions).

There's always a way of duck typing with all of its consequences. You
can try that if absolutely necessary.

obj == obj.window

should always be true when obj is a window.

It will always be false when obj is not a window, unless there is a DOM
object that has a window property pointing to itself. I can't really see
why that would be the case.

obj != obj.window

should always be true when obj is not a window.

The full code:

This checkin:
http://github.com/GarrettS/ape-java...699d3224bb137a18267813ec07af/src/dom/Event.js

Diff (can have comments added):
http://github.com/GarrettS/ape-java...5500d29e9c699d3224bb137a18267813ec07af#diff-6

Master:
http://github.com/GarrettS/ape-javascript-library/blob/master/src/dom/Event.js

Function cleanUp is added if isMaybeLeak, but that is done only when
`get` is called.

Method `get` uses function rewriting pattern, adding the returned
constructor and its prototype to the scope.

Although I haven't had much time to reflect on the design. The biggest
frustration I have had so far with it is testing it. YUI Test is only
helpful to a point.

YUI Test lacks support for dispatching focus and blur events. I added
that, added support for Apple's deplorable Touch Events API, made a few
patches, but I realize YUI Test still lacks creation of synthesized
window events, such as load/unload.

I could patch those, but then there are other pains of that API design
to deal with. One big pains is the event generation methods being so
long. When debugging, I have:
Action.click(testNode);

- and the YUI Test method for generating that event is one statement:
call another function. That other function is exceedingly long, so I
don't want to step through all of that. However, If I step over that one
statement that calls the long function, I don't get step into the
callback. Since most dom events are synchronous in browsers, I can step
keep clicking next until the browser transfers control from event
generating function to the (first) event callback for that event.
However, if I do step into that method, it is about 40 some clicks to
get to the callback. That hurts my hands and wastes time. Then there is
the issue of errors that get swallowed. Then there is the lack of stack
trace (I patched that to get it to work in a few browsers, at least).

I'd file more bugs the other bugs I've filed still haven't been fixed.
Even the patches I've submitted did not get integrated.
 
G

Garrett Smith

kangax said:
[...]

Doesn't have to be a DOM object. Could be any object that has `window`
property referencing object itself.

It must be an object that has attachEvent or addEventListener.
(function(){
var o = { };
o.window = o;
return (o.window == o); // true
})();

That won't likely happen because the object is duck-type checked:-

if(!src.addEventListener && !src.attachEvent) {
throw TypeError(src+ " is not a compatible object.");
}

What has either attachEvent or addEventListener, plus a window property
pointing to itself?
Well, in IE `window === window` is false. Where's guarantee that `window
== window` won't be false either?
AISI, window === window.window being false IE is a bug of IE. I don't
understand why that is. At best it is a "quirk" of IE.

The specification makes wide loopholes for host objects, but we do know
that global is an object, and if global === other is true, than other is
the global object (and so is an Object, by implication).

this === window in global context, and so the only way this.window !==
window could be true, is if the window object were resolved off the
variable object (which is, by design fault, a different object in IE,
going back to Eric Lippert's blog[1]).

In that case, if the window object were resolved on the variable object,
it could be a different object then that referred to by the global
object's window property, and in that case, then window == global.window
should be false.

In global context, has `window == this.window` ever been observed to be
false?

Strict equals `this.window === window` is false in IE, but that is part
of the bug I am working around.
But then again, as it stands now, I don't see a safe way to detect
window in cross-browser manner, and avoid chance of false positives
(it's either duck-typing or self-referencing comparison like the one you
mention; both can fail).

Maybe, but I can't think of a case where an object has attachEvent and
has a window property that is == to itself.

[...]
Why not avoid cleanup completely?

The cleanup helps older versions of IE (IE6 SP1 and earlier) remove
references. IE memory leak error got fixed in IE6 SP2 and is in in IE7.
With the fix, when a page is navigated away, the references get
cleaned up.

Another consideration not yet accounted for is events attached to
objects where an ancestor's innerHTML changes, removing the object. In
that case, the object should be purgeable, by say Event.purge(obj).

[...]
Have you considered writing your own testing lib?

Yes I have considered writing a testing framework. It is a lot of work.
Even more work to rewrite all of my tests that are using YUI Test. I
suppose the rewriting of unit tests might be at least partially
alleviated by creating aliases and adapters.

As they say, if you want something done right, do it yourself. Well I
am, but it is a lot of work. It isn't exactly easy to find good
developers and even harder to find good developers who want to work for
free on somebody else's (my) project.

I have made a lot of checkins in the 8 months, so was busy with those
things, but yes, I am considering writing a unit test framework.

[1]http://blogs.msdn.com/ericlippert/archive/2005/05/04/414684.aspx
 
D

David Mark

Garrett said:
kangax said:
kangax wrote:
On 2/8/10 7:49 PM, Garrett Smith wrote:
I'm confuse
[...]

Doesn't have to be a DOM object. Could be any object that has `window`
property referencing object itself.

It must be an object that has attachEvent or addEventListener.
(function(){
var o = { };
o.window = o;
return (o.window == o); // true
})();

That won't likely happen because the object is duck-type checked:-

if(!src.addEventListener && !src.attachEvent) {
throw TypeError(src+ " is not a compatible object.");
}

What has either attachEvent or addEventListener, plus a window property
pointing to itself?
Well, in IE `window === window` is false. Where's guarantee that
`window == window` won't be false either?
AISI, window === window.window being false IE is a bug of IE. I don't
understand why that is. At best it is a "quirk" of IE.

The specification makes wide loopholes for host objects, but we do know
that global is an object, and if global === other is true, than other is
the global object (and so is an Object, by implication).

this === window in global context, and so the only way this.window !==
window could be true, is if the window object were resolved off the
variable object (which is, by design fault, a different object in IE,
going back to Eric Lippert's blog[1]).

In that case, if the window object were resolved on the variable object,
it could be a different object then that referred to by the global
object's window property, and in that case, then window == global.window
should be false.

In global context, has `window == this.window` ever been observed to be
false?

Strict equals `this.window === window` is false in IE, but that is part
of the bug I am working around.
But then again, as it stands now, I don't see a safe way to detect
window in cross-browser manner, and avoid chance of false positives
(it's either duck-typing or self-referencing comparison like the one
you mention; both can fail).

Maybe, but I can't think of a case where an object has attachEvent and
has a window property that is == to itself.

[...]
Why not avoid cleanup completely?

The cleanup helps older versions of IE (IE6 SP1 and earlier) remove
references. IE memory leak error got fixed in IE6 SP2 and is in in IE7.
With the fix, when a page is navigated away, the references get cleaned
up.

But that doesn't answer the question. Why not avoid that issue entirely
by not creating circular references? I have the same sort of cleanup in
mine, which I will be removing (or at least making optional) when I get
around to it, as it is superfluous. Unload listeners should be avoided
at all costs as they foul up navigation, increasing server hits and
testing user patience.
 
G

Garrett Smith

kangax said:
Garrett said:
kangax wrote: [...]
Why not avoid cleanup completely?


The cleanup helps older versions of IE (IE6 SP1 and earlier) remove
references. IE memory leak error got fixed in IE6 SP2 and is in in IE7.
With the fix, when a page is navigated away, the references get
cleaned
up.

But that doesn't answer the question. Why not avoid that issue entirely
by not creating circular references? I have the same sort of cleanup in
mine, which I will be removing (or at least making optional) when I get
around to it, as it is superfluous. Unload listeners should be avoided
at all costs as they foul up navigation, increasing server hits and
testing user patience.

Well, this isn't really an issue, as you would only perform cleanup in
IE (e.g. <8), and those versions of IE (at least 6 and 7, last time I
checked) don't have fast history navigation.
I am not doing cleanup for IE7. That is called only where cc identifies
the script engine that shipped with the same engine that IE6 shipped with.

A reference to the DOM object is saved as a property of the wrapped
function and used fixing the context in callback.call(obj, callback).
That wrapped function is only used internally.

Once that object reference is saved, it needs to be removed to break the
circular reference (because IE won't).

The function Object has a `context` property pointing to a DOM object.

fun.context --> DOM obj

When a function is attached to a DOM object using attachEvent, IE
associates that function using an internal reference, as:

DOM obj --> fun

Put those together an you get:
DOM obj --> fun --> fun.context --> DOM obj.

To break that, I use:
delete fun.context.

I believe that will break the cycle.
 
D

David Mark

kangax said:
Garrett said:
kangax wrote: [...]
Why not avoid cleanup completely?


The cleanup helps older versions of IE (IE6 SP1 and earlier) remove
references. IE memory leak error got fixed in IE6 SP2 and is in in IE7.
With the fix, when a page is navigated away, the references get
cleaned
up.

But that doesn't answer the question. Why not avoid that issue entirely
by not creating circular references? I have the same sort of cleanup in
mine, which I will be removing (or at least making optional) when I get
around to it, as it is superfluous. Unload listeners should be avoided
at all costs as they foul up navigation, increasing server hits and
testing user patience.

Well, this isn't really an issue, as you would only perform cleanup in
IE (e.g. <8), and those versions of IE (at least 6 and 7, last time I
checked) don't have fast history navigation.

And how do you suggest to tell it is definitely IE < 8. I suppose you
could resort to conditional compilation plus various object inferences,
but, as you mentioned, why not avoid all of that?

Are you sure? ISTM that they do, though perhaps not in the same sense
as the other majors. Perhaps rather than preserving the DOM, it
preserves the initial state of the DOM, in which case unload listeners
won't matter. Still no reason to bother with such complications.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,079
Messages
2,570,575
Members
47,207
Latest member
HelenaCani

Latest Threads

Top