From: David Mark on
On Jan 3, 6:32 am, Hans-Georg Michna <hans-
georgNoEmailPle...(a)michna.com> wrote:
> On Fri, 01 Jan 2010 15:36:22 -0800, Garrett Smith wrote:
> >Hans-Georg Michna wrote:
> >>> The example code, the callback for document.onreadystatechange changes
> >>> context from document to window.
> >> Oops, didn't even notice. What's the simplest way to do it
> >> better? How do you even know what the original context was?
> >When the function's internal [[Call]] property is invoked, if the `this`
> >value is not an object (null is not an object), then the `this` value is
> >the global object. Saving the value of document.onreaystatechange in an
> >identifier, the identifier gets the functional value. When the call
> >operator is used on that identifier, the base object is null and so the
> >this value is the global object.
>
> >var oldReadyHandler = document.onreadystatechange;
>
> Thanks a lot for the excellent explanations!
>
> So would it solve this inaccuracy to save the handler
> temporarily in the document object, rather than in a variable,
> such as:
>
> document.onreadystatechangeOld = document.onreadystatechange;

No. That solves nothing and could create big problems. Try it in IE
after this:-

document.expando = false;

You never augment host objects.

>
> Then later, when it is no longer needed, use:
>
> delete document.onreadystatechangeOld;

Nor do you attempt to delete their properties.

>
> By the way, null is an object,

The null value is not an object, regardless of what its typeof result
might seem to indicate.

> unlike undefined, which is not an
> object.
> Perhaps the original designer of JavaScript had a hiccup
> when he wrote this. (:-)

Perhaps. The typeof result seems pretty idiotic (look at the
confusion it causes). :)

>
> Still null is not very suitable, so »this« perhaps defaults to
> the global object in case of null.

As described in the specs.

>
> >Really, I'd just go with window.onload.
>
> Done. Looks much cleaner and simpler too.

Just remember that you are stepping on the onload attribute of the
body.

>
> >Another approach to consider is adding the script to the bottom
> >and just invoking it.
>
> Yes, thought about that, but it gives the web designer who uses
> the script another opportunity to do something wrong.

I've heard the "our users are idiots" argument ad nauseam, even from
frameworks that ostensibly target programmers. Now, for Web
developers, I can see it, but the DOM ready trick should be an
optional second script. It's no more complicated to paste one script
in the head and an optional second script at the end. Hell, call the
second putatendofbody.js.

>
> Also, in a Content Management System the script user may only be
> able to get to the bottom of his content, not to the ultimate
> bottom of the page code, which may cause problems in some cases.

No question there.
From: Garrett Smith on
Hans-Georg Michna wrote:
> On Fri, 01 Jan 2010 15:36:22 -0800, Garrett Smith wrote:
>
>> Hans-Georg Michna wrote:
>
>>>> The example code, the callback for document.onreadystatechange changes
>>>> context from document to window.
>
>>> Oops, didn't even notice. What's the simplest way to do it
>>> better? How do you even know what the original context was?
>
>> When the function's internal [[Call]] property is invoked, if the `this`
>> value is not an object (null is not an object), then the `this` value is
>> the global object. Saving the value of document.onreaystatechange in an
>> identifier, the identifier gets the functional value. When the call
>> operator is used on that identifier, the base object is null and so the
>> this value is the global object.
>>
>> var oldReadyHandler = document.onreadystatechange;
>
> Thanks a lot for the excellent explanations!
>

Sure. I also suggest reading the specification for "Function Calls" in
ECMA-262 r3.

You can read an unofficial online edition:-
http://bclary.com/2004/11/07/#a-11.2.3

Also for Function Code:
http://bclary.com/2004/11/07/#a-10.2.3

That is neither a normative reference nor a disgusting PDF format.

> So would it solve this inaccuracy to save the handler
> temporarily in the document object, rather than in a variable,
> such as:
>
> document.onreadystatechangeOld = document.onreadystatechange;

No, not an expando.

>
> Then later, when it is no longer needed, use:
>
> delete document.onreadystatechangeOld;
>

Definitely not that. Calling delete on a Host object in IE will usually
throw an error.

I would use Function.prototype.call instead.

function readyStateChangeHandler(ev) {
ev = ev || window.event;
if(oldready) {
oldready.call(this, ev);
}
}

The callback can use

function theOriginalReadyHandler(ev){
if(this.readyState == "complete") alert("complete");
}

and it should work as expected.

> By the way, null is an object, unlike undefined, which is not an
> object. Perhaps the original designer of JavaScript had a hiccup
> when he wrote this. (:-)
>

No, null is not an object; null is a primitive value.

Notice that the table for the `typeof` operator has special handling for
`null`. There was another thread not too long ago with VK, I think
kangax' review for "Professional JavaScript" that explained about null.

> Still null is not very suitable, so �this� perhaps defaults to
> the global object in case of null.
>

That's what happens in function calls in ES3.

[...]

>
>> Another approach to consider is adding the script to the bottom
>> and just invoking it.
>
> Yes, thought about that, but it gives the web designer who uses
> the script another opportunity to do something wrong.
>
> Also, in a Content Management System the script user may only be
> able to get to the bottom of his content, not to the ultimate
> bottom of the page code, which may cause problems in some cases.
>

It may cause problems when requiring the elements to be rendered
completely (measuring offsetWidth, or style values).

> So I'll stick to window.onload and hope that the DOM
> specification designers one day see the light and give us what
> we really need.
>

HTML 5 specifies DOMContentLoaded. There isn't a good way to detect if
the browser will fire that event (or other DOM events).

The un-detectible "activation" and "domfocusin" event proposals had the
same predicament and died for the same reasons.
--
Garrett
comp.lang.javascript FAQ: http://jibbering.com/faq/
From: Garrett Smith on
David Mark wrote:
> On Jan 3, 6:32 am, Hans-Georg Michna <hans-
> georgNoEmailPle...(a)michna.com> wrote:
>> On Fri, 01 Jan 2010 15:36:22 -0800, Garrett Smith wrote:
>>> Hans-Georg Michna wrote:
>>>>> The example code, the callback for document.onreadystatechange changes
>>>>> context from document to window.
>>>> Oops, didn't even notice. What's the simplest way to do it
>>>> better? How do you even know what the original context was?
>>> When the function's internal [[Call]] property is invoked, if the `this`
>>> value is not an object (null is not an object), then the `this` value is
>>> the global object. Saving the value of document.onreaystatechange in an
>>> identifier, the identifier gets the functional value. When the call
>>> operator is used on that identifier, the base object is null and so the
>>> this value is the global object.
>>> var oldReadyHandler = document.onreadystatechange;
>> Thanks a lot for the excellent explanations!
>>
>> So would it solve this inaccuracy to save the handler
>> temporarily in the document object, rather than in a variable,
>> such as:
>>
>> document.onreadystatechangeOld = document.onreadystatechange;
>
> No. That solves nothing and could create big problems. Try it in IE
> after this:-
>
> document.expando = false;

Is there any good reason to set document.expando = false?

If you do that the `unselectable` property won't work.

>
> You never augment host objects.
>
Augmenting host objects is error prone.

scrollBy.x = 1; // IE Error.

[...]

Also for DOM objects that have DOM readonly. This might seem to map to
ECMAScript ReadOnly but you shouldn't expect that. Assignment to a DOM
readonly property must be disallowed whether or not an exception is
thrown depends on the language.

In ES5 Strict mode, assigning to a property where [[Writable]] is false
or assigning to a property with a getter but no setter, will result in
TypeError. Assinging to an undeclared identifier will too.

Implementations are known to use a getter for DOM readonly.

When trying to set a property with a getter and no setter, the result is
an Error. Here is an example:-

document.onclick = function(ev){
// Try to modify DOM readonly clientX
// http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-MouseEvent
ev.clientX = 10;
};

Run that, then lick the document in Firefox and see:

| "Error: setting a property that has only a getter"
--
Garrett
comp.lang.javascript FAQ: http://jibbering.com/faq/
From: John G Harris on
On Sun, 3 Jan 2010 at 22:27:11, in comp.lang.javascript, Garrett Smith
wrote:
>Hans-Georg Michna wrote:

<snip>
>> By the way, null is an object, unlike undefined, which is not an
>> object. Perhaps the original designer of JavaScript had a hiccup
>> when he wrote this. (:-)
>>
>
>No, null is not an object; null is a primitive value.
<snip>

That's true now, but there are signs that it was different in the far
distant past. It looks as though it was originally thought of as an
object pointer that happens to have a null value, as in Java, C++, etc.

As a result some ancient parts of javascript still call it an object,
and they are too ancient to be changed. Possibly it's sometimes
implemented as an object pointer with a null value, but this is not
visible from outside.

John
--
John Harris
From: Lasse Reichstein Nielsen on
John G Harris <john(a)nospam.demon.co.uk> writes:

> On Sun, 3 Jan 2010 at 22:27:11, in comp.lang.javascript, Garrett Smith
> wrote:
>>Hans-Georg Michna wrote:

>>No, null is not an object; null is a primitive value.
> <snip>
>
> That's true now, but there are signs that it was different in the far
> distant past. It looks as though it was originally thought of as an
> object pointer that happens to have a null value, as in Java, C++, etc.

Now you are guessing.

Anyway, in Java, null is not an object either. It's an Object
Reference value, referring to no object, and there is a different null
value of each object type.

In JavaScript, you don't have type requirements, so you just need one
null value, and it's still not an object - so it's a primitive value.

Whether it's really necessary to have both null and undefined (and
not, e.g., just two names for the same value) is a different
discussion.
I guess that the idea was to allow people to write something that
looked like Java. :)

> As a result some ancient parts of javascript still call it an object,
> and they are too ancient to be changed. Possibly it's sometimes
> implemented as an object pointer with a null value, but this is not
> visible from outside.

Indeed. And it's a royal pain the the backside that (typeof o ==
"object") doesn't guarantee that it's actually an object.

/L
--
Lasse Reichstein Holst Nielsen
'Javascript frameworks is a disruptive technology'