Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Window load/unload calling Object.prototype extension method.

4 views
Skip to first unread message

Zvt.Fred

unread,
Apr 7, 2009, 4:45:08 PM4/7/09
to
Hi people,

When I extend the Object's prototype like this:

Object.prototype.zvt_hello = function() {
alert("Hello object! (" + this.toString() + ")");
}

var d = new Date();
d.zvt_hello();

var i = new Number();
i.zvt_hello();

I noted that zvt_hello() method is called in window.onload and
window.onunload.
I tested on FF 3.0.8 and IE 6.0.2.

Can anyone explain me why this happens?

Thanks everyone!
Fred

Thomas 'PointedEars' Lahn

unread,
Apr 7, 2009, 5:33:05 PM4/7/09
to

You call it there. (That was easy.)


PointedEars

Zvt.Fred

unread,
Apr 7, 2009, 6:44:55 PM4/7/09
to
> You call it there.  (That was easy.)

When I do:

Object.prototype.zvt_hello = function() {
alert("Hello object! (" + this.toString() + ")");
}

I'm also calling this function?
I think I just create a new function and assigned to property
'zvt_hello' of Object's prototype.
I'm expecting the function to be called just in d.zvt_hello(); and
i.zvt_hello();

Can you clarify me?

Thanks a lot for your help.
Fred

Thomas 'PointedEars' Lahn

unread,
Apr 8, 2009, 4:42:46 AM4/8/09
to
Zvt.Fred wrote:
>> You call it there. (That was easy.)
>
> When I do:
>
> Object.prototype.zvt_hello = function() {
> alert("Hello object! (" + this.toString() + ")");
> }
>
> I'm also calling this function?

No.

> I think I just create a new function and assigned to property
> 'zvt_hello' of Object's prototype.

Correct.

> I'm expecting the function to be called just in d.zvt_hello(); and
> i.zvt_hello();

Also correct.

> Can you clarify me?

"There" means whatever you think `window.onload' or `window.unonload' is.

JFTR: The method is not called in my Firefox (Iceweasel) 3.0.6. However, it
is a Bad Idea to augment Object.prototype because all native and some host
objects inherit from it; thus augmentation there makes for-in iteration a
lot harder.

Please don't remove the attribution lines.


PointedEars

Zvt.Fred

unread,
Apr 8, 2009, 1:13:55 PM4/8/09
to
On Apr 8, 5:42 am, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

Well, what I'm trying to understand is exactly this strange behavior.
I don't see why this method is been called on load/unload of the
window automatically. Anyway, I leave the idea of augment
Object.prototype already, but still curious about this.

Even more curious now that you said that in Iceweasel it doesn't
happen. Maybe some friend with Windows can test it for us. Just
augment Object with some dummy method and look for automatic calls in
window load/unload.

Thank you very much, PointedEars.

Fred.

David Mark

unread,
Apr 8, 2009, 3:44:36 PM4/8/09
to
On Apr 8, 4:42 am, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

Yes, it will break poorly designed scripts (like jQuery, Mootools,
etc.), which do not take into account that native object prototypes
can be augmented. This is why "mash-ups" tend to get mashed up,
ground up and are ultimately spat out.

[snip]

Thomas 'PointedEars' Lahn

unread,
Apr 8, 2009, 4:32:15 PM4/8/09
to
David Mark wrote:
> Thomas 'PointedEars' Lahn wrote:

>> Zvt.Fred wrote:
>>> Can you clarify me?
>> "There" means whatever you think `window.onload' or `window.unonload' is.
>>
>> JFTR: The method is not called in my Firefox (Iceweasel) 3.0.6. However, it
>> is a Bad Idea to augment Object.prototype because all native and some host
>> objects inherit from it; thus augmentation there makes for-in iteration a
>> lot harder.
>
> Yes, it will break poorly designed scripts (like jQuery, Mootools,
> etc.), which do not take into account that native object prototypes
> can be augmented. This is why "mash-ups" tend to get mashed up,
> ground up and are ultimately spat out.

It will break all scripts that use for-in iteration, not only poorly
designed ones. And if you are saying that for-in iteration is a bad
idea per se, we have to disagree.


PointedEars

Garrett Smith

unread,
Apr 10, 2009, 2:49:13 AM4/10/09
to

In your first post, you posted code that calls the "zvt_hello" method twice.

What makes you certain that the method was called from onload and onunload?

Changing your code slightly:-

<script type="text/javascript">
Object.prototype.zvt_hello = function() {
alert(this.constructor);
}

var d = new Date();
d.zvt_hello();
var i = new Number();
i.zvt_hello();

</script>

- results in two alerts:

function Date(){
[native code]
}

function Number(){
[native code]
}

<aside>
Those don't conform to ECMA 262r3
| 15.3.4.2 Function.prototype.toString()
|
| An implementation-dependent representation of the function is
| returned. This representation has the syntax of a FunctionDeclaration.
</aside>

Garrett

Zvt.Fred

unread,
Apr 10, 2009, 11:48:02 AM4/10/09
to

I'll have to apologize with you guys for make such a noobie mistake.
In the html file that I was using to test the code that I first send
jQuery 1.3.2 was being imported and only in this situation the
zvt_hello method was called in window load/unload, though i didn't
know why since i find very hard to have a call to a method named
zvt_hello inside jQuery and doesn't make sense to me that in window
load/unload event handlers jQuery calls any extension to Object. Maybe
that kind of break that David Mark was telling about in his response.

Garrett, why you think that don't conforms to ECMA specifications?
When you call d.zvt_hello() and i.zvt_hello() your implementation was
executed but Date and Number constructor functions are alerted because
you tell to do so in alert(this.constructor).

Thanks everybody.
Fred

Timo Reitz

unread,
Apr 10, 2009, 12:13:21 PM4/10/09
to
Zvt.Fred schrieb:

>> function Date(){
>> [native code]
>> }
>>
>> function Number(){
>> [native code]
>> }
>>
>> <aside> Those don't conform to ECMA 262r3 | 15.3.4.2
>> Function.prototype.toString() | | An implementation-dependent
>> representation of the function is | returned. This representation has
>> the syntax of a FunctionDeclaration. </aside>
>
> Garrett, why you think that don't conforms to ECMA specifications? When
> you call d.zvt_hello() and i.zvt_hello() your implementation was executed
> but Date and Number constructor functions are alerted because you tell to
> do so in alert(this.constructor).

They don't conform to it because

function Number(){
[native code]
}

is not a valid FunctionDeclaration.

Garrett Smith

unread,
Apr 11, 2009, 1:49:37 AM4/11/09
to
Zvt.Fred wrote:
> On Apr 10, 3:49 am, Garrett Smith <dhtmlkitc...@gmail.com> wrote:
>> Zvt.Fred wrote:
>>>> You call it there. (That was easy.)
>>> When I do:
>>> Object.prototype.zvt_hello = function() {
>>> alert("Hello object! (" + this.toString() + ")");
>>> }
>>> I'm also calling this function?
>>> I think I just create a new function and assigned to property
>>> 'zvt_hello' of Object's prototype.
>>> I'm expecting the function to be called just in d.zvt_hello(); and
>>> i.zvt_hello();
>>> Can you clarify me?
>> In your first post, you posted code that calls the "zvt_hello" method twice.
>>
>> What makes you certain that the method was called from onload and onunload?
>>

[...]

> I'll have to apologize with you guys for make such a noobie mistake.

AFAIK, this question has never come up here.

> In the html file that I was using to test the code that I first send
> jQuery 1.3.2 was being imported and only in this situation the
> zvt_hello method was called in window load/unload, though i didn't
> know why since i find very hard to have a call to a method named

You say you did not know why, but you did not state how you were certain
that this code was called in load/unload. Your example did not back up
your claim.

> zvt_hello inside jQuery and doesn't make sense to me that in window

Ah, you failed to provide a test case that included jQuery! Now I'm
getting more of the picture.

> load/unload event handlers jQuery calls any extension to Object. Maybe
> that kind of break that David Mark was telling about in his response.
>

It is possible that there is a for in loop somewhere:-

for(var p in obj) {
if(jQuery.isFunction(obj(p)) {

...

I can change that test case to include jQuery and, if it is
reproducible, find exactly why.

However, before doing that, there is one question, The unload behavior
is observable by cause and effect. So the question is: What makes you
think the function was called from the window's load event?

> Garrett, why you think that don't conforms to ECMA specifications?

Exactly for the reason that Timo Reitz provided. Please see the
production for FunctionDeclaration.

> When you call d.zvt_hello() and i.zvt_hello() your implementation was
> executed but Date and Number constructor functions are alerted because
> you tell to do so in alert(this.constructor).
>
> Thanks everybody.
> Fred

Garrett

Zvt.Fred

unread,
Apr 11, 2009, 7:55:55 AM4/11/09
to

I'm not sure that this function was called on load/unload anymore,
when I run this html:

<html><head><title></title>
<script type="text/javascript" src="../jQuery/jquery-1.3.2.min.js" ></
script>
<script type="text/javascript">

Object.prototype.zvt_hello = function() {
alert(this.constructor);
}

var d = new Date();
d.zvt_hello();

var i = new Number();
i.zvt_hello();

</script></head><body></body></html>

I receive this alerts (in order):

In Firefox 3.0.8 In IE 6.0.2

1. [object Window] undefined

2. function Date() { function Date() {
[native code] [native code]
} }

3. function Number() { function Number() {
[native code] [native code]
} }

4. [object Window] undefined

And when I unload the page (calling another page), I receive another:

5. [object Window] undefined

However I'm sure that is a behavior caused be the insertion of jQuery
because if I remove its inclusion, I receive only the 2nd and 3rd
alerts. But I don't think this can be caused be the jQuery.isFunction
helper method since its implementation is as follows (in v.1.3.2):

(...)
isFunction: function( obj ) {
return toString.call(obj) === "[object Function]";
},
(...)

And if I run toString.call(d.zvt_hello) I'll obtain "[object
Function]", not another call to that function.

Also, i continue not understanding why function() { [native code] } is
not a valid FunctionDeclaration if in ECMAScript Specs 262 r3 the
specification is as follows:

FunctionDeclaration :
function Identifier ( FormalParameterListopt ) { FunctionBody }

It's because of the [native code] placeholder?

Fred.


Thomas 'PointedEars' Lahn

unread,
Apr 11, 2009, 3:18:19 PM4/11/09
to
Garrett Smith wrote:
> <script type="text/javascript">
> Object.prototype.zvt_hello = function() {
> alert(this.constructor);
> }
>
> var d = new Date();
> d.zvt_hello();
> var i = new Number();
> i.zvt_hello();
> </script>
>
> - results in two alerts:
>
> function Date(){
> [native code]
> }
>
> function Number(){
> [native code]
> }
>
> <aside>
> Those don't conform to ECMA 262r3

You are mistaken because alert() is a host method (of Window objects, and
should therefore be called window.alert()). It may display anything there.


PointedEars

David Mark

unread,
Apr 11, 2009, 3:41:01 PM4/11/09
to
On Apr 8, 4:32 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

> David Mark wrote:
> > Thomas 'PointedEars' Lahn wrote:
> >> Zvt.Fred wrote:
> >>> Can you clarify me?
> >> "There" means whatever you think `window.onload' or `window.unonload' is.
>
> >> JFTR: The method is not called in my Firefox (Iceweasel) 3.0.6.  However, it
> >> is a Bad Idea to augment Object.prototype because all native and some host
> >> objects inherit from it; thus augmentation there makes for-in iteration a
> >> lot harder.
>
> > Yes, it will break poorly designed scripts (like jQuery, Mootools,
> > etc.), which do not take into account that native object prototypes
> > can be augmented.  This is why "mash-ups" tend to get mashed up,
> > ground up and are ultimately spat out.
>
> It will break all scripts that use for-in iteration, not only poorly
> designed ones.

[snip]

Okay, I'll bite. Where are you getting that from?

Garrett Smith

unread,
Apr 11, 2009, 3:59:23 PM4/11/09
to

unload of previous document may have fired here.

> 2. function Date() { function Date() {
> [native code] [native code]
> } }
>
> 3. function Number() { function Number() {
> [native code] [native code]
> } }

Result of calling the function (your calls).

>
> 4. [object Window] undefined
>

load event may have fired here.

> And when I unload the page (calling another page), I receive another:
>
> 5. [object Window] undefined
>

That could be unload.

> And if I run toString.call(d.zvt_hello) I'll obtain "[object
> Function]", not another call to that function.
>

toString being a property of the global object would be window.toString.
Calling that in context of a function would likely fail (and superficial
testing results in an error in Firefox).

Here is my new test case:-

<script type="text/javascript" src="../../jslib/jquery-1.3.2.js"></script>
<script type="text/javascript">
Object.prototype.zvt_hello = function(e) {
alert([e && e.type, arguments.callee.caller.caller].join("\n\n"));
}
</script>

Result:-
| load
|
| function () {
| return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
| jQuery.event.handle.apply(arguments.callee.elem, arguments) :
| undefined;
|
| }

(similar with unload).

Look at jQuery source: That string is an anonymous function that is
created in (and only in) the jQuery.event |add| method.

So what you stated was in fact true.

As to why jQuery adds this, lets look at the caller to jQuery.event.add:-

| jQuery.event = {
| // Bind an event to an element
| // Original by Dean Edwards
| add: function(elem, types, handler, data) {
| if ( elem.nodeType == 3 || elem.nodeType == 8 )
| return;
| // (GS) added debug alert statement.
| alert(arguments.callee.caller + "\n\n" +
| 'arguments:\n '+[].join.call(arguments, '\n ');
|

Running the example code, I see:

| fn:
| function (event) {
| jQuery(this).unbind(event, one);
| return (fn || data).apply(this, arguments);
| }

- that's jQuery.fn.one.

| fn:
| function () {
| if (!jQuery.isReady) {
| jQuery.isReady = true;
| if (jQuery.readyList) {
| jQuery.each(jQuery.readyList, function () {
| this.call(document, jQuery);});
| jQuery.readyList = null;
| }
| jQuery(document).triggerHandler("ready");
| }
| }

- that's jQuery.ready.

> Also, i continue not understanding why function() { [native code] } is
> not a valid FunctionDeclaration if in ECMAScript Specs 262 r3 the
> specification is as follows:
>
> FunctionDeclaration :
> function Identifier ( FormalParameterListopt ) { FunctionBody }
>
> It's because of the [native code] placeholder?
>

FunctionBody :
SourceElements

-->

SourceElements :
SourceElement
SourceElements SourceElement

-->

SourceElement :
Statement
FunctionDeclaration

So the content of a FunctionDeclaration must contain a Statement or a
FunctionDeclaration.
"[native code]" is not a FunctionDeclaration. Is it a statement?
Have a look:

Statement :
Block
VariableStatement
EmptyStatement
ExpressionStatement
IfStatement
IterationStatement
ContinueStatement
BreakStatement
ReturnStatement
WithStatement
LabelledStatement
SwitchStatement
ThrowStatement
TryStatement


> Fred.
>
>

Garrett

Thomas 'PointedEars' Lahn

unread,
Apr 11, 2009, 4:07:26 PM4/11/09
to

Sorry, I don't follow. Maybe if you didn't snip this much you had got my
meaning?


PointedEars

Garrett Smith

unread,
Apr 11, 2009, 11:55:05 PM4/11/09
to

The alert method converts its argument to a string value.

window.alert( '' + this.constructor );

would have the same effect of popping up an alert box with the [native
code] function representations.

<aside>
Although this is invalid, certain libraries actually depend on this
behavior. Dojo, Mootools, and Qooxdoo, for example perform tests to see
if the result of converting an object to a string (using its toString)
contains "[native code]".

This practice is not just non-standard, even if the [native code] were
allowed it is fallible on two counts that have been discussed.
</aside>

Garrett

kangax

unread,
Apr 12, 2009, 5:23:33 PM4/12/09
to
Garrett Smith wrote:
> Thomas 'PointedEars' Lahn wrote:
[...]

>> You are mistaken because alert() is a host method (of Window objects, and
>> should therefore be called window.alert()). It may display anything
>> there.
>>
>>
>
> The alert method converts its argument to a string value.

It's surprising that neither MDC, nor MSDN nor HTML5 draft mention
anything about `alert` performing such conversion.

>
> window.alert( '' + this.constructor );
>
> would have the same effect of popping up an alert box with the [native
> code] function representations.
>
> <aside>
> Although this is invalid, certain libraries actually depend on this
> behavior. Dojo, Mootools, and Qooxdoo, for example perform tests to see
> if the result of converting an object to a string (using its toString)
> contains "[native code]".
>
> This practice is not just non-standard, even if the [native code] were
> allowed it is fallible on two counts that have been discussed.
> </aside>

Yes. Some mobile clients have very diverse function representations. I
actually had similar concerns about function decompilation and wrote
about a more reliable way to detect built-in host methods [1].
Unfortunately, my solution is not perfect either, since it relies on
iframe insertion into a document.

[1] http://thinkweb2.com/projects/prototype/detecting-built-in-host-methods/

--
kangax

Garrett Smith

unread,
Apr 13, 2009, 3:27:08 AM4/13/09
to
kangax wrote:
> Garrett Smith wrote:
>> Thomas 'PointedEars' Lahn wrote:
> [...]
>>> You are mistaken because alert() is a host method (of Window objects,
>>> and
>>> should therefore be called window.alert()). It may display anything
>>> there.
>>>
>>>
>>
>> The alert method converts its argument to a string value.
>
> It's surprising that neither MDC, nor MSDN nor HTML5 draft mention
> anything about `alert` performing such conversion.
>

MDC is not perfect.

MSDN is a crapshoot. Some of the documentation is good. However, a lot
it is pretty poor.

HTML5 - I'll post that on the list.

>
> Yes. Some mobile clients have very diverse function representations. I
> actually had similar concerns about function decompilation and wrote
> about a more reliable way to detect built-in host methods [1].
> Unfortunately, my solution is not perfect either, since it relies on
> iframe insertion into a document.

Which ones?

You might also want to let PPK know about that.

>
> [1]
> http://thinkweb2.com/projects/prototype/detecting-built-in-host-methods/
>

Your article says you are testing for something in a "non-modified"
context. I assume this means that the context is the newly created
iframe's window object is un-buggered.

Why not just not give the global object an addEventListener property?

Oh, maybe because "somebody might have done that."

In that case that same somebody might not have used standards mode
(doctype) and the document created in the iframe might use standards
mode. Or vice versa (hopefully not that(!)).

You also mention speed. The iframe will also have to be garbage
collected and that will slow things down a bit, too.

There is one other consideration. A pretty serious one, too. In IE,
appending a child mid-parse will result in a lovely "operation aborted"
error[1][2]. This makes the page stop rendering and basically kills your
webapp. So: If your blog is "perfection kills", then I guess you could
call this strategy of appending a node to body while it is being parsed
"perfection".

j/k

:-)

So this:-
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Detecting built-in host methods</title>
</head>
<body>

<div>
<script type="text/javascript">

var isNativeWindowAddEventListenerPresent = (function(global){
// feature test following methods as needed
var el = document.createElement('iframe');
var root = document.body || document.documentElement;
root.appendChild(el);
var frame = global.frames[global.frames.length-1];
var result = (typeof frame.addEventListener != "undefined");
//root.removeChild(el);
el = null;
return result;
})(this);

</script></div>

</body>
</html>


would result in "operation aborted" error in IE.

The example, as it is written on your blog, gets away with it when the
root.removeChild line is uncommented (as it appears there). It also
works when you don't put the script in a div (which I purposely added to
trigger the error in IE). There should not be a good reason to have that
div anyway. The problem is avoidable, in most cases.

When adding test nodes to body while it is possibly being parsed, I like
use insertBefore(body.firstChild, testEl) instead of appendChild. I have
not had a problem with that yet. I think D Mark and I discussed this
technique about a year ago in "Find Element Position" thread (though I
may be mistaken; we did exchange a good amount of email during that time).

Garrett

[1]http://support.microsoft.com/kb/927917
[2]http://blogs.msdn.com/ie/archive/2008/04/23/what-happened-to-operation-aborted.aspx

kangax

unread,
Apr 13, 2009, 5:51:30 PM4/13/09
to
Garrett Smith wrote:
> kangax wrote:
[...]

>> It's surprising that neither MDC, nor MSDN nor HTML5 draft mention
>> anything about `alert` performing such conversion.
>>
[...]

> HTML5 - I'll post that on the list.

Great.

>
>>
>> Yes. Some mobile clients have very diverse function representations. I
>> actually had similar concerns about function decompilation and wrote
>> about a more reliable way to detect built-in host methods [1].
>> Unfortunately, my solution is not perfect either, since it relies on
>> iframe insertion into a document.
>
> Which ones?
>
> You might also want to let PPK know about that.

Blackberry ones return something like - "function XMLHttpRequest(){
[native code for XMLHttpRequest.XMLHttpRequest, arity=1] }"

There are other variations which, IIRC, look something like -

"function anonymous(){ [af33e43d4dac65578932567d] }"

>
>>
>> [1]
>> http://thinkweb2.com/projects/prototype/detecting-built-in-host-methods/
>>
>
> Your article says you are testing for something in a "non-modified"
> context. I assume this means that the context is the newly created
> iframe's window object is un-buggered.

Yes. It's basically used as a clean snapshot of a client environment.

>
> Why not just not give the global object an addEventListener property?
>
> Oh, maybe because "somebody might have done that."

The idea is to determine whether a method (or any non-native object for
that matter) is a built-in host object or if it is the one created via a
third party script. For example, one might want to know if
`document.getElementsByClassName` is a method provided by a third party
script, rather than an environment itself (for perf. or other reasons).

>
> In that case that same somebody might not have used standards mode
> (doctype) and the document created in the iframe might use standards
> mode. Or vice versa (hopefully not that(!)).

As I understand, it is possible to determine rendering mode of a main
document and trigger the same one in the iframe context. Or not?

>
> You also mention speed. The iframe will also have to be garbage
> collected and that will slow things down a bit, too.

Yes, iframe-based solution is somewhat cumbersome. It's too bad that
creating an iframe and inserting it into a document has so many
implications. Having a "clean" context could be very useful in
environments with high level of pollution. Till recently, Prototype.js,
for example, was overwriting JS 1.8 `Array.prototype.reduce` without
first testing for its existence. If your script happened to run together
with Prototype.js, you would not be able to use fast native `reduce`
(or `map`, `filter`, and others, for that matter). Fortunately,
Prototype.js stopped overwriting `reduce` some time ago, but there is
still plenty of pollution going on.

>
> There is one other consideration. A pretty serious one, too. In IE,
> appending a child mid-parse will result in a lovely "operation aborted"
> error[1][2]. This makes the page stop rendering and basically kills your

Ah. That was stupid of me.

[snip example and explanation]

>
> When adding test nodes to body while it is possibly being parsed, I like
> use insertBefore(body.firstChild, testEl) instead of appendChild. I have
> not had a problem with that yet. I think D Mark and I discussed this
> technique about a year ago in "Find Element Position" thread (though I
> may be mistaken; we did exchange a good amount of email during that time).

Thanks. I've seen `insertBefore` used in such cases but never bothered
to find out why it's being preferred over `appendChild`.

Do you know of any cases when insertion of an arbitrary element into a
`document.documentElement` (at the moment when `document.body` is not
yet available) causes any problems?

So far, inserting an INPUT element (to invoke `click` and test for event
object properties) into `document.documentElement` has been working
pretty smoothly on every client that I could get my hands on.


[...]

--
kangax

0 new messages