IE leaks, circular references, addevent et al

R

Richard Maher

Hi,

I'd like to thank David Mark for recently sending me a copy of his MyLib.js
library and for responding to some of my questions here in c.l.js. (Let me
also take the opportunity to thank all of you who have responded with
assistance to my posts!).

As it happens, my requirements are more pedestrian/light-weight when it
comes to the event-listener requirements than the full-throttle
all-encompassing functionality that David's library provides so I hope
someone/anyone can assist on a dumbed-down event listener strategy.

Attached below with listenerRegistry.checkIn and chekOut is (what I think
is) all I need. The fly in the oinment here would appear to be
circular-references and IE's memory leakage issues. Now, I'm more than happy
to stick an ONUNLOAD handler in there and loop through the registry (like
David's and many other strategys have done) but is it really needed in this
case? Will there be leakage and do I have to cater for it?

Also if there's much else that's bollocks with the example please let me
know.

Cheers Richard Maher

var listenerRegistry = function() {

var globalVar = function(){return this;}();
var actionListeners = {};

var checkIn = function(){

if (window.addEventListener) {
return function(element, eventName, handler) {
element.addEventListener(eventName, handler, false);
};
}

if (window.attachEvent) {
return function(element, eventName, handler) {
if (actionListeners[element + eventName + handler])
return;

var normalizedHandler =
function() {
handler.call(
actionListeners[element + eventName +
handler].el,
globalVar.event);
};
actionListeners[element + eventName + handler] =
{el : element, fn : normalizedHandler};
if (!element.attachEvent('on' + eventName,
normalizedHandler))
throw new Error("Unable to attach listener");
};
}
}();

var checkOut = function(){

if (window.removeEventListener) {
return function(element, eventName, handler) {
element.removeEventListener(eventName, handler, false);
};
}

if (window.detachEvent) {
return function(element, eventName, handler) {
if (!actionListeners[element + eventName + handler])
throw new Error("Unable to detach listener");

element.detachEvent('on' + eventName,
actionListeners[element + eventName +
handler].fn);
actionListeners[element + eventName + handler].el = null;
actionListeners[element + eventName + handler].fn = null;
actionListeners[element + eventName + handler] = null;
};
}
}();

return {
checkIn : checkIn,
checkOut : checkOut
};
}();
 
D

David Mark

Hi,

I'd like to thank David Mark for recently sending me a copy of his MyLib.js
library and for responding to some of my questions here in c.l.js. (Let me
also take the opportunity to thank all of you who have responded with
assistance to my posts!).

As it happens, my requirements are more pedestrian/light-weight when it
comes to the event-listener requirements than the full-throttle
all-encompassing functionality that David's library provides so I hope
someone/anyone can assist on a dumbed-down event listener strategy.
Thanks.


Attached below with listenerRegistry.checkIn and chekOut is (what I think
is) all I need. The fly in the oinment here would appear to be
circular-references and IE's memory leakage issues. Now, I'm more than happy
to stick an ONUNLOAD handler in there and loop through the registry (like
David's and many other strategys have done) but is it really needed in this
case? Will there be leakage and do I have to cater for it?

Actually, as mentioned a ways back, the unload listener isn't needed
in my rendition.
Also if there's much else that's bollocks with the example please let me
know.

I'll look at it when I get a chance. One thing sticks out:

actionListeners[element + eventName + handler] =
{el : element, fn : normalizedHandler};

Think about what those keys will look like.
 
A

abozhilov

On Sep 15, 3:31 pm, "Richard Maher" <[email protected]>
wrote:

Hi Richard Maher.
actionListeners[element + eventName + handler]

That isn't good. You explicit case `element` to string. That element
is host object. Will be implementation depended toString. And if
doesn't excite operation like that, will be throw error. You have and
another problem.
If i have two button.
Code:
<button>click</button>
<button>click</button>
In IE6/7 when cast this object to string. Results is '[object]'. In
IE8 '[object HTMLButtonElement]';
If i use your code to attach to this two button same handler on same
event type. I can't do that. Because:
if (actionListeners[element + eventName + handler])
return;
Btw:

var globalVar = function(){return this;}();

Interesting line, to get reference to 'Global Object'. This is
usefully and independ of `this` value in running execution
context.
 
R

Richard Maher

Hi David,

David Mark said:
Actually, as mentioned a ways back, the unload listener isn't needed
in my rendition.

Cool bananas!
I'll look at it when I get a chance. One thing sticks out:
actionListeners[element + eventName + handler]

Ok, if I replace "element" by artificially appending a unique _MyID (or as
has been discussed) requiring and vetting that the element has a .ID
attribute, then actionListeners[element._MyId + eventName + handler] should
sort it out?
Think about what those keys will look like.

Thanks. Looks like initial success with event-listeners on a couple of
checkboxes left me glossing over things.

Cheers Richard Maher
 
G

Garrett Smith

Richard said:
Hi David,



Cool bananas!

Have you identified a memory leak?

IE6 updated over a year ago to address the famous COM_OBJ -> jscript ->
COM_OBJ leak.

I would definitely avoid using an unload listener where possible. I
would also tend to favor DOM 0 type registry where eventhandlers are
properties and not address any specific event models, along with all the
associated bugs/quirks.

Why?

DOM 0 events are widely implemented and fairly consistent.

The type of registry can work with hand-rolled events that the program
creates (functions for events).

The registry could not cover all possible event-related quirks. YUI and
jQuery have tried to address a lot of the quirks but end up being very
complicated in the process.

My favorite event registry is APE EventPublisher because it does only
that.

For some reason Thunderbird is not wrapping lines.

Tools > Options > Composition:
Wrap plain text messages at [72] characters.
 
D

David Mark

Have you identified a memory leak?

Plenty of times.
IE6 updated over a year ago to address the famous COM_OBJ -> jscript ->
COM_OBJ leak.
So?


I would definitely avoid using an unload listener where possible.
Right.

I
would also tend to favor DOM 0 type registry where eventhandlers are
properties and not address any specific event models, along with all the
associated bugs/quirks.

I like DOM0, but I never really needed a registry. The one in My
Library uses DOM0 as a last resort, but I don't think anyone should
ever need it.
Why?

DOM 0 events are widely implemented and fairly consistent.
Yes.


The type of registry can work with hand-rolled events that the program
creates (functions for events).

What type of registry?
The registry could not cover all possible event-related quirks. YUI and
jQuery have tried to address a lot of the quirks but end up being very
complicated in the process.

Who cares what they did?
My favorite event registry is APE EventPublisher because it does only
that.

Of course. :)

[snip]
 
R

RobG

On Sep 15, 3:31 pm, "Richard Maher" <[email protected]>
wrote: [...]
Btw:

 var globalVar = function(){return this;}();

Interesting line, to get reference to 'Global Object'. This is
usefully and independ of `this` value in running execution
context.

Yes, though as it is only used within the normalizedHandler function,
some may prefer to declare it there to:

1. avoid unnecessary closures (though here it likely makes
no difference as a closure to actionListeners is maintained
anyway)

2. associate it more closely in the code with the scope
within which it is used
 
R

Richard Maher

Hi Garett,

Garrett Smith said:
Have you identified a memory leak?

IE6 updated over a year ago to address the famous COM_OBJ -> jscript ->
COM_OBJ leak.

I would definitely avoid using an unload listener where possible. I
would also tend to favor DOM 0 type registry where eventhandlers are
properties and not address any specific event models, along with all the
associated bugs/quirks.

Why?

DOM 0 events are widely implemented and fairly consistent.

The type of registry can work with hand-rolled events that the program
creates (functions for events).

The registry could not cover all possible event-related quirks. YUI and
jQuery have tried to address a lot of the quirks but end up being very
complicated in the process.

My favorite event registry is APE EventPublisher because it does only
that.

Umm, let me be quite clear that I'm not suffering from conviction on this
issue and have an open mind as to what is the "best" approach to handling
events. Having said that, isn't the main drawback of the DOM 0 approach,
that you appear to be advocating, the fact that you can only register *one*
event handler for each event type on a given object? Isn't this the main
reason we're all here looking for alternatives, or have I missed something?

Cheers Richard Maher
 
R

Richard Maher

Hi abozhilov,

On Sep 15, 3:31 pm, "Richard Maher" <[email protected]>
wrote:

Hi Richard Maher.
actionListeners[element + eventName + handler]
That isn't good.

Yep. Hopefully fixed that, please see below. (Sorry for the lack of testing
before and now)

I think we're all agreed that the Javascript Object class/prototype/whatever
needs, or at least could benefit from, a hashCode() method/function.
Interesting line, to get reference to 'Global Object'. This is
usefully and independ of `this` value in running execution
context.

Yeah, that's what someone said on the web somewhere so I thought it was
useful :)

Cheers Richard Maher

Take II: -

var listenerRegistry = function() {

var globalVar = function(){return this;}();
var actionListeners = {};
var targetId = 1;

var checkIn = function(){

if (window.addEventListener) {
return function(element, eventName, handler) {
element.addEventListener(eventName, handler, false);
};
}

if (window.attachEvent) {
return function(element, eventName, handler) {
if (!element._evtId)
element["_evtId"] = targetId++;
if (actionListeners[element._evtId + eventName + handler])
return;

var normalizedHandler =
function() {
handler.call(
actionListeners[element._evtId +
eventName + handler].el,
globalVar.event);
};
actionListeners[element._evtId + eventName + handler] =
{el : element, fn : normalizedHandler};
if (!element.attachEvent('on' + eventName,
normalizedHandler))
throw new Error("Unable to attach listener");
};
}

throw new Error("Unsupported Browser");
}();

var checkOut = function(){

if (window.removeEventListener) {
return function(element, eventName, handler) {
element.removeEventListener(eventName, handler, false);
};
}

if (window.detachEvent) {
return function(element, eventName, handler) {
if (!element._evtId)
throw new Error("No event registered on this Object");
if (!actionListeners[element._evtId + eventName + handler])
throw new Error("Unable to detach listener");

element.detachEvent('on' + eventName,
actionListeners[element._evtId +
eventName + handler].fn);
actionListeners[element._evtId + eventName + handler].el =
null;
actionListeners[element._evtId + eventName + handler].fn =
null;
actionListeners[element._evtId + eventName + handler] =
null;
element._evtId = null;
};
}

throw new Error("Unsupported Browser");
}();

return {
checkIn : checkIn,
checkOut : checkOut
};
}();
 
G

Garrett Smith

Richard said:
Hi Garett,



Umm, let me be quite clear that I'm not suffering from conviction on this
issue and have an open mind as to what is the "best" approach to handling
events. Having said that, isn't the main drawback of the DOM 0 approach,
that you appear to be advocating, the fact that you can only register *one*
event handler for each event type on a given object? Isn't this the main
reason we're all here looking for alternatives, or have I missed something?


Don't get me wrong, I'm not trying to convince you to use APE
EventPublisher at all.

To have multiple callbacks in DOM 0 events, keep an array of functions
and call them in a loop. It is a fairly well-known pattern, though not
the easiest one to write.

There is an object that binds the src that fires the event with the
callback list.

When the actual event is fired, the function that handles the callback
calls each function in the array. This is done in a try catch so that if
any one of the callbacks throws an error, it does not stop the execution
of the event notification.

This is can be useful for user-defined objects that will fire custom
events (I called them "hand rolled" earlier):

Animation.prototype = {
onend : noop,
onstart : noop
// ...
};

I can use:

var bird = new Animation;
EventPublisher.add(bird, "onend", birdOnEndHandler);
function birdOnEndHandler(onEndEvent) {
// do something with bird.
}

Within Animation "class", there is a call to onend function. In this
case EventPublisher.fire is added, and so that function gets called, and
then EventPublisher.fire goes about the task of calling everything that
was added to it.

In a case where a program would know that there is only going to be one
callback, the code could be simply:-

bird.onend = birdOnEndHandler;
div.onclick = divClickHandler;

Now that's great, but to make it happen, a closure is used.

When adding callbacks to a DOM node, the result is:

DOM_NODE -> JScript Function -> [[Scope]] -> DOM_NODE

The problem is that this leaks in older versions of IE6.

This can be ameliorated by breaking the link by setting DOM_NODE event
handler to null:

div.onclick = null

This works, but then when this is done onunload, it interferes with
bfcache.
https://developer.mozilla.org/En/Using_Firefox_1.5_caching

| If a page uses an unload handler, it fires when the user navigates
| away from the page. If an unload handler is present, the page will not
| be cached.

EventPublisher adds an onload handler if the jscript build is < 5.7. I
can't say I like this inference much, but it allows for bfcache most of
the time, while cleaning up sources of memory leaks in IE6.
 
R

Richard Maher

Hi Garrett,

Garrett Smith said:
Richard said:
Umm, let me be quite clear that I'm not suffering from conviction on this
issue and have an open mind as to what is the "best" approach to handling
events. Having said that, isn't the main drawback of the DOM 0 approach,
that you appear to be advocating, the fact that you can only register *one*
event handler for each event type on a given object? Isn't this the main
reason we're all here looking for alternatives, or have I missed
something?


Don't get me wrong, I'm not trying to convince you to use APE
EventPublisher at all.

To have multiple callbacks in DOM 0 events, keep an array of functions
and call them in a loop. It is a fairly well-known pattern, though not
the easiest one to write.

There is an object that binds the src that fires the event with the
callback list.

When the actual event is fired, the function that handles the callback
calls each function in the array. This is done in a try catch so that if
any one of the callbacks throws an error, it does not stop the execution
of the event notification.

This is can be useful for user-defined objects that will fire custom
events (I called them "hand rolled" earlier):

Animation.prototype = {
onend : noop,
onstart : noop
// ...
};

I can use:

var bird = new Animation;
EventPublisher.add(bird, "onend", birdOnEndHandler);
function birdOnEndHandler(onEndEvent) {
// do something with bird.
}

Within Animation "class", there is a call to onend function. In this
case EventPublisher.fire is added, and so that function gets called, and
then EventPublisher.fire goes about the task of calling everything that
was added to it.

In a case where a program would know that there is only going to be one
callback, the code could be simply:-

bird.onend = birdOnEndHandler;
div.onclick = divClickHandler;

Now that's great, but to make it happen, a closure is used.

When adding callbacks to a DOM node, the result is:

DOM_NODE -> JScript Function -> [[Scope]] -> DOM_NODE

The problem is that this leaks in older versions of IE6.

This can be ameliorated by breaking the link by setting DOM_NODE event
handler to null:

div.onclick = null

This works, but then when this is done onunload, it interferes with
bfcache.
https://developer.mozilla.org/En/Using_Firefox_1.5_caching

| If a page uses an unload handler, it fires when the user navigates
| away from the page. If an unload handler is present, the page will not
| be cached.

EventPublisher adds an onload handler if the jscript build is < 5.7. I
can't say I like this inference much, but it allows for bfcache most of
the time, while cleaning up sources of memory leaks in IE6.

Thanks for the explanation on the APE EventPublisher! It looks very useful
and flexible. But I'm just looking for a light-weight, KISS example of
attaching event handlers that works with most browsers, takes care of
"this", and the "event" parameter to the handler.

I can see many benefits to your approach and I hope many people *choose*
your library, but compelling people to use your code by introducing a
dependence is not something I want to do at the mo.
Cheers Richard Maher
 
R

Richard Maher

Hi Rob,

RobG said:
Yes, though as it is only used within the normalizedHandler function,
some may prefer to declare it there to:

You/some would execute the same code over and over in the normalizeHandler
function rather than just one at startup/instantiation-time just to put the
definition "close" to where it is used?

Cheers Richard MAher
 
G

Garrett Smith

Richard said:
Hi Garrett,

Garrett Smith said:
Richard Maher wrote:
[snip]
EventPublisher adds an onload handler if the jscript build is < 5.7. I
can't say I like this inference much, but it allows for bfcache most of
the time, while cleaning up sources of memory leaks in IE6.

Thanks for the explanation on the APE EventPublisher! It looks very useful
and flexible. But I'm just looking for a light-weight, KISS example of
attaching event handlers that works with most browsers, takes care of
"this", and the "event" parameter to the handler.

EventPublisher does not resolve the event parameter, but does resolve
the |this| value. It can also be used for custom events, which I find
very useful.
I can see many benefits to your approach and I hope many people *choose*

APE is AFL 3.0, so those seeing to use a registry for commercial uses
would not want to choose it.

For now, I am interested in improving the code quality and code reviews
on it can help.

Anyone who spots a problem can comment on it right there in GitHub or
here. Juriy has commented on several of mine and I on his. Github is a
neat site, though awfully slow.

Beware: There is another APE JavaScript Framework that was created
sometime after mine. I have nothing to do with that.

The author of the other APE JavaScript "Framework" has expressed strong
interest in SEO, I learned of its existence via adsense ads in my gmail.
The knock-off APE JavaScript has a different license (I believe this may
be illegal), is based on mootools, has pretty graphics.
The real APE: http://github.com/GarrettS/ape-javascript-library/
 
R

RobG

Hi Rob,



You/some would execute the same code over and over in the normalizeHandler
function rather than just one at startup/instantiation-time just to put the
definition "close" to where it is used?

I was talking more in general.

globalVar can be declared and initialised just before the
normalizedHandler function so that it is only assigned a value if that
fork is executed (which is once only in IE-like browsers). The closure
will only be one level deep so quick to resolve if that matters
(possibly not in this particular case).

It can be declared inside the normalizedHandler function to remove the
closure (for globalVar) and will be initialised on every call. The
criterion for which one to pick is whether initialising it takes
longer than resolving it over the scope chain with a 1 level closure -
quick tests show it is a lot slower to initialise every time. Even so,
it takes 10,000 calls for the time to become significant (i.e. more
than about 50ms on my fairly average PC).

Other tests have shown that when resolving variables over the scope
chain, shorter is better. So in this case I'd initialise it as deep as
is reasonable, i.e. just before the normalizedHandler function.

I guess now someone (PE?) will point out that what you're really after
is window.event, not globalVar.event.

window === globalVar // false

but that doesn't seem to matter here, the associated event object
properties seem to be practically equivalent even though the objects
themselves aren't:

window.event == globalVar.event // false
window.event.srcElement == globalVar.event.srcElement // true

No doubt there is a thread somewhere here about that.
 
T

Thomas 'PointedEars' Lahn

RobG said:
[...]
Other tests have shown that when resolving variables over the scope
chain, shorter is better. So in this case I'd initialise it as deep as
is reasonable, i.e. just before the normalizedHandler function.

I guess now someone (PE?) will point out that what you're really after
is window.event, not globalVar.event.

window === globalVar // false

but that doesn't seem to matter here, the associated event object
properties seem to be practically equivalent

Those who think that "doesn't seem to matter" and "are practically
equivalent" are marks of good software quality, may do so. All others
should prefer the reasonable and documented approach.

In fact, the length of the effective scope chain can be made exactly the
same with `window' and `globalVar' if one assigned a reference to `window'
to a local variable (different from `globalVar') and used that variable if,
and only if, properties of the Window object are to be accessed in the local
execution context.
even though the objects themselves aren't:
window.event == globalVar.event // false
window.event.srcElement == globalVar.event.srcElement // true

While what you describe may indeed be the case, your reasoning is flawed as
you are comparing host objects here.
No doubt there is a thread somewhere here about that.

Definitely.


PointedEars
 
D

David Mark

Richard Maher wrote:

[...]
Take II: -
    var listenerRegistry = function() {
       var globalVar = function(){return this;}();

`globalVar` is rather strange choice of name for a reference to Global
Object. I would instead go with `globalObject` or `global`.

Note that expression on the right hand side will unfortunately result in
`undefined` in ES5 strict mode (as per current draft).
       var actionListeners = {};
       var targetId = 1;
       var checkIn  = function(){
           if (window.addEventListener) {
             return function(element, eventName, handler){
                 element.addEventListener(eventName, handler, false);
               };
           }
           if (window.attachEvent) {

`else if` would probably be a better choice:

else if (window.attachEvent) { ...
// or
else if (typeof window.attachEvent != 'undefined') { ...
             return function(element, eventName, handler){
                 if (!element._evtId)

So you decided to augment host objects after all.
                   element["_evtId"] = targetId++;
                 if (actionListeners[element._evtId +eventName + handler])

This is still unreliable. `handler` is being type converted to string
here (so-called function decompilation); that string is implementation
dependent and the whole thing becomes rather fragile.

Last time I checked D. Mark was attaching a unique id onto `handler`
function object. It's not without its own problems but is better than
function decompilation.

Problems? What problems? Perhaps you mean that you could purposely
overwrite the _fnId property and break removal. But why would you do
that?
                   return;
                 var normalizedHandler =
                       function() {
                         handler.call(
                                    actionListeners[element._evtId +
eventName + handler].el,
                                    globalVar.event);

`globalVar.window.event` would be more reliable.

Would make more sense. In practice it hasn't mattered.
 
D

David Mark

David said:
Richard Maher wrote:
[...]
Take II: - [...]
                   element["_evtId"] = targetId++;
                 if (actionListeners[element._evtId+ eventName + handler])
This is still unreliable. `handler` is being type converted to string
here (so-called function decompilation); that string is implementation
dependent and the whole thing becomes rather fragile.
Last time I checked D. Mark was attaching a unique id onto `handler`
function object. It's not without its own problems but is better than
function decompilation.
Problems?  What problems?  Perhaps you mean that you could purposely
overwrite the _fnId property and break removal.  But why would you do
that?

Nothing major :)

Main problem as I see it is that it's obtrusive. You feed `addEvent`
with a function object and that function object is being injected with
some property you had no clue about.

Yes, in an academic sense, it is overstepping its bounds adding that
property.
Handler might have some other
properties and user might be iterating over those properties (perhaps
even adding/deleting them).

Pretty remote for a Function object, but possible.
In that case an addition of `_fnId` can have undesired side effects,
including inability to detach it (if `_fnId` is removed).
Yes.


I'm not sure how likely it is to happen but it seems like a real
possibility.

Nothing that can't be mentioned in docs, though.

Should be mentioned for sure.
Handler can also be a host object, so the whole thing might fail, but
that's a rather moot point, of course, and can be mentioned in
documentation too.

That goes without saying I think (I mean using a host object as a
listener). Not supported in any event.
 
D

David Mark

Alright.

There's another thing I meant to ask you. If I'm not mistaken, event
mechanism in "My Library" augments target with either "uniqueID" or
"_targetId" strings.

What do you know? There are some expsndos in there.
For example, `attachListener` delegates to
`addNormalizedListener` which in turn calls `getTargetId` which then
assigns unique "uniqueID" to an element (if not yet present) via
`elementUniqueId` method.

Yes and this is not a good practice.
I see that you are taking care of assignments on global object (by
always returning "_apiwin", although it looks like `window` objects of
other frames/windows will still be injected with properties),
Yes.

but I
don't understand:

1) Why any target that has falsy `tagName` gets special treatment and is
injected with unique `"_api" + uniqueTargetHandle`

Because I was avoiding expandos in IE by using their built-in unique
identifier, which doesn't work at all for document objects. All could
have been avoided, of course.
2) What you meant by once saying, IIRC, that event mechanism can easily
avoid expandos. Were you talking about using something like `id`
attribute (quite inconvenient, imo) or something else?

I definitely wasn't referring to requiring ID's to attach listeners.

If you look carefully at the element expando mentioned above, it is
handling two things. In attach, it guards against duplicates. That's
a waste of time (and ill-advised really). Removing that makes it no
less an event mechanism. :) The detach is where the real snag was
and clearly it is because the design was trying to do too much.
Surely there is a happy medium between that and requiring an ID for
every node (and how would that work for documents and windows anyway?)
3) Whether you had any problems with all this host objects augmentation
in any environment.

Not that I kmow of. Of course, I never used my library. ;) I do
know I have checks in there for document.expando === false, which
disallows them in IE. Happily IE doesn't use expandos due to its
inherent unique ID's. The ones it hangs on documents and frame
windows were always considered a design flaw. Same for the one that
some types of CSS queries add, but if then a CSS query engine is ill-
advised in the first place. An efficient one of those may not be
possible without expandos. Not sure as I haven't considered it in
years. ;)
 
T

Thomas 'PointedEars' Lahn

RobG said:
Thomas said:
RobG said:
[...]
Other tests have shown that when resolving variables over the scope
chain, shorter is better. So in this case I'd initialise it as deep as
is reasonable, i.e. just before the normalizedHandler function.
I guess now someone (PE?) will point out that what you're really after
is window.event, not globalVar.event.
window === globalVar // false
but that doesn't seem to matter here, the associated event object
properties seem to be practically equivalent
Those who think that "doesn't seem to matter" and "are practically
equivalent" are marks of good software quality, may do so. All others
should prefer the reasonable and documented approach.

It would help if you would provide a link to that approach.

It would help more if you simply read what was posted on the matter (by me)
so far. This is not news.
The issue here is how to guarantee a reference to window will be the
one expected. Presumably you are recommending something like:

var globalVar = (function(){return this;})();
var window = globalVar.window;

within a suitable context.

I would do that if I were overly paranoid, and would want to write
potentially incompatible code (considering ES 5+ may one day be implemented
as drafted). Instead, I am recommending something like

function ...(...) {
var w = window;

w...
}

or, if you must, like

var _global = this;

function ...(...) {
var w = _global.window;

w...
}

You are fishing for a problem to your solution here. When have you last
encountered code that had a property named `window' on the scope chain that
did _not_ refer to the same object as the `window' property of the Global
Object? When did you not first think about simply renaming the former
property, or replacing the code that introduced it with something better, as
you encountered its blocking your access to the Window instance in question?
Richard C explained that it seems that a new event object is created
each time window.event is read, however that the host-assigned
properties are the same for a particular event.

Yes, that is what can happen with *host objects* and their unspecified
[[Get]] method.
Link please?

No, STFW ('window event "=="', and the like.)


PointedEars
 
R

RobG

RobG said:
[...]
Other tests have shown that when resolving variables over the scope
chain, shorter is better. So in this case I'd initialise it as deep as
is reasonable, i.e. just before the normalizedHandler function.
I guess now someone (PE?) will point out that what you're really after
is window.event, not globalVar.event.
   window === globalVar  // false
but that doesn't seem to matter here, the associated event object
properties seem to be practically equivalent

Those who think that "doesn't seem to matter" and "are practically
equivalent" are marks of good software quality, may do so.  All others
should prefer the reasonable and documented approach.

It would help if you would provide a link to that approach.

In fact, the length of the effective scope chain can be made exactly the
same with `window' and `globalVar' if one assigned a reference to `window'
to a local variable (different from `globalVar') and used that variable if,
and only if, properties of the Window object are to be accessed in the local
execution context.

The issue here is how to guarantee a reference to window will be the
one expected. Presumably you are recommending something like:

var globalVar = (function(){return this;})();
var window = globalVar.window;

within a suitable context.

While what you describe may indeed be the case, your reasoning is flawed as
you are comparing host objects here.

Richard C explained that it seems that a new event object is created
each time window.event is read, however that the host-assigned
properties are the same for a particular event.

A trivial comparison of the properties of window.event and
globalVar.event seem to agree with that, I haven't done the exhaustive
testing of events, properties and contexts required to confirm it's
veracity in depth. I was hoping that if it had been done (or
equivalent work, since Richard rarely makes such statements without
appropriate research), a link might be provided to some documentation
of it.

Definitely.

Link please?
 

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

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top