J
What do you think about this ?
Quoting from that page:
| I proposed an alternative to him [Crockford] which looked like this,
| again, minus the alert and validation:
|
| var showNumber_Rewrite=function(i){
| alert('This is called when it is needed, but only once');
| var n=['Zero','One','Two','Three','Four','Five','Six',...];
| showNumber_Rewrite=function(i){
| if(!(i in n))return 'Invalid Number';
| return n;
| };
| return showNumber_Rewrite(i);
| }
|
| The difference is this does not execute at all until it is actually
| needed. The first time it is called, the array is created and the
| function itself is rewritten, creating a closure, such that each
| subsequent call just validates and returns the string. Unlike his
| example, if you never need it, it never executes.
This isn't new; see here for more examples:http://peter.michaux.ca/articles/lazy-function-definition-pattern
| He didn’t like it. He couldn’t give me a real reason.
Sounds like Crockford alright.
It's a useful pattern, especially when you want to return different
versions of a function, but need to wait for the first call before you
decide which version to use. One example where this is useful is when
you load the function in the document head, but need access to
document.body.
I'm not so sure about the mentioned performance benefit; I'd need to see
(or do) benchmarks before I use this just to save "a few cycles".
By the way, the "validation" added by the author uses "i in n" to check
for the existence of array elements, which is a bad idea for obvious
reasons:
showNumber_Rewrite("join");
There are also a few gotchas with this approach. One is the possibility
of memory leaks (see the comments on Peters blog). And if you use
something like the following, it will rewrite the function on every call:
var myAlias = showNumber_Rewrite;
myAlias(2);
myAlias(2);
myAlias(2);
This will show three alerts. You could avoid that by storing the result
of the expensive calculations in arguments.callee.cached, and have the
function return this value if it exists.
- Conrad
Conrad said:
Quoting from that page:
| I proposed an alternative to him [Crockford] which looked like this,
| again, minus the alert and validation:
|
| var showNumber_Rewrite=function(i){
| alert('This is called when it is needed, but only once');
| var n=['Zero','One','Two','Three','Four','Five','Six',...];
| showNumber_Rewrite=function(i){
| if(!(i in n))return 'Invalid Number';
| return n;
| };
| return showNumber_Rewrite(i);
| }
|
| The difference is this does not execute at all until it is actually
| needed. The first time it is called, the array is created and the
| function itself is rewritten, creating a closure, such that each
| subsequent call just validates and returns the string. Unlike his
| example, if you never need it, it never executes.
This isn't new; see here for more examples:
http://peter.michaux.ca/articles/lazy-function-definition-pattern
| He didn’t like it. He couldn’t give me a real reason.
Sounds like Crockford alright.
Conrad said:It's overkill in the showNumber example, I agree. There are other
situations where it could actually be useful; for example measuring the
browser's viewport area. Such a function could be called a number of
times in short succession if it's used in an onresize handler. Rewriting
the function, or (better) storing the appropriate sub-function as a
property of arguments.callee, could lead to a measurable performance
difference there.
I prefer keeping code as readable as possible,
Conrad Lender said:It's overkill in the showNumber example, I agree. There are other
situations where it could actually be useful; for example measuring the
browser's viewport area. Such a function could be called a number of
times in short succession if it's used in an onresize handler. Rewriting
the function, or (better) storing the appropriate sub-function as a
property of arguments.callee, could lead to a measurable performance
difference there.
Lasse said:If you are going for performance, I wouldn't use arguments.callee (or
a global variable for that matter) to access the function.
Using arguments.callee is likely to trigger creation of the arguments
object, which an optimized JS implementation would otherwise avoid if
the "arguments" variable isn't used. It will cause a slowdown on each
call to the function.
Thomas 'PointedEars' Lahn said:Lasse said:If you are going for performance, I wouldn't use arguments.callee
(or a global variable for that matter) to access the function.
Using arguments.callee is likely to trigger creation of the
arguments object, which an optimized JS implementation would
otherwise avoid if the "arguments" variable isn't used. It will
cause a slowdown on each call to the function.
Such an optimized "JS" implementation would not be conforming as
the ECMAScript Language Specification, Edition 3 Final, section
10.1.8, says that "the `arguments' object" "is [to be] created
and initialised" "when control enters an execution context for
function code", and _not_ when it is first used.
Your recommendation is not valid.
<snip>On the JSLint list, I've seen a number of very short replies
from you to questions or feature requests that I thought
deserved more of an explanation. Other messages didn't receive
any response at all. JSLint is such an important tool for JS
developers; it can be quite frustrating when its author appears
unresponsive to suggestions and criticism.
Richard said:It is worth remembering that - arguments - objects have a dynamic
linkage with the Variable object's 'formal parameter' properties
(theoretically open-ended, but never implemented as such) and
facilitating that means a bit more work than simply creating a new
native ECMAScript object.
It also appears, from discussions on the ES 3.1 discussion mailing lists
between some of the people who have written some of the implementations
currently in use, that current implementations frequently don't create
arguments objects for execution contexts in which they are not
referenced.
I recall that years ago (5 or 6) I argued with Douglas Crockford on this
group about whether JSLint should be objecting to 'fall through' in -
switch - structures. I was in favour of allowing it, JSLint had other
ideas, and no amount of talk of 'issues' caused by it was going to
convince me otherwise.
Given that I can entirely understand an unwillingness on Douglas' part
to carry on that discussion. He may well have thought 'he wants to learn
the hard way, so let him', and left it at that.
Thomas 'PointedEars' Lahn said:Lasse said:If you are going for performance, I wouldn't use arguments.callee (or
a global variable for that matter) to access the function.
Using arguments.callee is likely to trigger creation of the arguments
object, which an optimized JS implementation would otherwise avoid if
the "arguments" variable isn't used. It will cause a slowdown on each
call to the function.
Such an optimized "JS" implementation would not be conforming as the
ECMAScript Language Specification, Edition 3 Final, section 10.1.8, says
that "the `arguments' object" "is [to be] created and initialised" "when
control enters an execution context for function code", and _not_ when it
is first used. Your recommendation is not valid.
Thomas 'PointedEars' Lahn said:Richard Cornford wrote:
All the more reason why it does not make sense to create the object only
when referenced. If created only when execution reached the relevant
statement, that would slow down execution. The alternative to that is to
scan the entire function body for `arguments' when control enters the
execution context, to see if the reference is there, which also is not very
efficient. Better create it always, as the Spec says.
Apparently those people have not thought through what that would mean in a
production environment.
Interesting. I've just tested this in FF2 and Opera 9.63, and I can
confirm that using the arguments object is noticably slower (about 30%
of the maximum in Opera, and 1-2 orders of magnitude in FF2). Unless I
made a mistake in my benchmark (see below).
Interesting. I've just tested this in FF2 and Opera 9.63, and I can
confirm that using the arguments object is noticably slower (about 30%
of the maximum in Opera, and 1-2 orders of magnitude in FF2). Unless I
made a mistake in my benchmark (see below).
That would either mean an additional step for the user of the function,
or you couldn't place the script in the <head>, because the detection
requires access to document.body.
Lasse said:Thomas 'PointedEars' Lahn said:Lasse said:If you are going for performance, I wouldn't use arguments.callee (or
a global variable for that matter) to access the function.
Using arguments.callee is likely to trigger creation of the arguments
object, which an optimized JS implementation would otherwise avoid if
the "arguments" variable isn't used. It will cause a slowdown on each
call to the function.
Such an optimized "JS" implementation would not be conforming as the
ECMAScript Language Specification, Edition 3 Final, section 10.1.8, says
that "the `arguments' object" "is [to be] created and initialised" "when
control enters an execution context for function code", and _not_ when it
is first used. Your recommendation is not valid.
The specification defines semantics, not implementation.
Whether you actually create the arguments object when the function is
entered, or when the arguments object is first used, is indistinguishable
and all javascript programs will behave the same in the two cases.
I.e., the semantics are identical.
Anyway, I was not saying that the arguments object was created later,
but that it is created at all. If the "arguments" variable is
definitly not used inside a function, then an implementation can
entirely avoid creating it and save time and space in doing so - still
without changing the semantics of any program.
/L 'If tree doesn't fall in the forest, and nobody is looking, does
it still take time and space?'
They are not. It takes time to create the object, and creating it only when
execution reaches the point when it is first used, would slow down
execution.
Fair enough, but how can you be sure that the run time required for
additonal parsing does not compensate for the run time that might be gained
by not creating the `arguments' object when not being referred to?
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.