R
Richard Cornford
There you go again.
And there you go again. Instead of being interested in why I think 50%
of what you wrote is somewhere between uninformed and nonsense you would
rather disregard the comment and leave it as it is.
The subject is expected NOT to be any of those things.
If the subject (the value that is subject to the tests) were not
expected to be a string what would be the point of seeing how the
results of - typeof - compared with 'string'? If it could not be a
string then the outcome would be known at the point of writing the code
and no runtime test would be required. The same goes for every other
test.
The point of each test is to exclude these things.
If the subject of the test is not expected to potentially be the things
that are excluded there is no point making any effort to exclude them.
Just maybe, there's
some type of node that says it's a "function" to typeof.
There is nothing to say that an object implementing the Node interface
should not be a function object.
It's actually likely in Safari; Safari thinks document.images
is a function, which it is Not!
Fist you must state what it is that defined 'a function'. One completely
rational and justifiable definition of 'a function' in ECMAScritp terms
could be "an object that can be called" (i.e. subject to the 'call
operator' without that act of itself directly resulting in an exception
being thrown (later exceptions, such as winging about the types or
number of arguments are not related to the callability of the object)).
Under that definition Safari's - document.images - is a function, as it
can be called.
Now I should clear up a bit of confusion you posted on the
webkit bug:
Take an object that is an instance of an NodeList.
NodeList is an interface not a 'class'. Which is a good thing, as
ECMAscript/javascript has no notion of 'classes'. But even in
class-based languages like Java an object implementing an interface is
not necessarily an object of any particular (or any single) class.
Javascript is a very flexible language and it loves interfaces. You can
take an object, any object, and retro-fit an interface to it at runtime.
And you can add the interface to any number of objects with very diverse
origins to the extent that they have nothing else in common that could
be regarded as asserting their 'type'.
The result is that any notion of "an instance of an NodeList" has very
little meaning in javascript. It may or may not reflect an internal
implementation detail, but beyond that it is no more than a perception
in the mind of a programmer.
That object's constructor implements NodeList.
Absolutely nothing, anywhere, makes any assertions about constructors in
relation to object that implement the NodeList interface.
The object itself is an object.
An object implementing the NodeList interface must be an object, but is
not required to be anything more. And it can be expected to be a host
object, so almost nothing else can be asserted about it with authority.
The fact that it is callable is a bug,
No. Object can be callable. At least the things that are callable in
javascript are all objects.
copied from MSIE, who made document.all, etc. a function,
e.g. document.all(0). Mozilla copied this.
And copied by nearly every other browser since, with a significant
proportion of them also returning 'function' from - typeof - operations
on those objects.
It is retarded, IMO.
It is certainly unnecessary and unhelpful, but it is (and has for some
considerable time been) a reality.
javascript:alert(Function.prototype.call.call(
document.links,document, 1))
Not really useful. OR good design.
An instance of a NodeList is NOT the object that
implements NodeList.
An object that implements the NodeList interface is precisely what the
W3C DOM specifications define it as. Making any assertion beyond that
would be technically groundless.
The object that implement's NodeList is the instance's
constructor.
Can you find any authorities statement supporting that assertion?
Neither of the applicable documents (Core DOM and its ECMAScript
bindings and ECMA 262) are that big so it should not take too long to
look.
What objects are those?
Objects that inherit from functions.
Only ones that incorrectly report "function"
for typeof, I hope.
Have you identifier any objects that do "incorrectly" report 'function'?
We have seen that the objects that are concerning you are callable
(which would be a fine justification for reporting 'function') and that
they are host objects (so they may report anything at all). Where does
your definition of "incorrectly" come from?
What I prefer about the dojo function
This is the dojo function:-
| if(dojo.isBrowser && dojo.isSafari){
| // only slow this down w/ gratuitious casting in Safari since
| // it's what's b0rken
| dojo.isFunction = function(/*anything*/ it){
| if((typeof(it) == "function") && (it == "[object NodeList]")){
| return false;
| }
| return (typeof it == "function" || it instanceof Function);
| }
| }else{
| dojo.isFunction = function(/*anything*/ it){
| return (typeof it == "function" || it instanceof Function);
| }
| }
is at least it is less inclusive.
It filters out with the typeof operator.
document.links instanceof Function; // false in Safari.
But it will include any non-function object that has a function on its
prototype chain, so the objects that are 'isFunction' are not
necessarily even executable. It makes you wonder what it is they think
they are testing for.
That's what I'm saying. If jQuery's isFunction gets a falsish value,
a string value, et c, that value is excluded. It's "none of", not
"any of". You're wrong.
No I am right. If the subject of the test (the value that is tested)
were not expected to be any of those possibilities then there would be
no point in testing them with the intention of excluding them.
http://www.m-w.com/dictionary/betray
I'm pretty sure you meant "betrays good design," as that's the
gist of what you're saying.
It is in the nature of bad design that it attempts to hide. Here the bad
design has been exposed by the test code. The bad design has been
betrayed by the code and so its attempt to hide from observation has
been unsuccessful. Thus the test code betrays the bad design.
When I use others' code, I want it to fail right away if I use it
wrong. Now it might have been my fault for passing in an undefined,
but hey, I'm human and I lose my keys, I've put shit in the washer
that shouldn't go there, (phone, et c).
When others use my code it should fail fast and report the error
properly.
Now if some library had a function that takes a callback, that would
be when you want to know "is the callback a function?"
It would be better to have some more precise definition of what you
meant by 'a function' here. Do you just mean something that can be
called, or do you really want to discriminate between programmer defined
functions and everything else? Pinning down precisely what you need to
know is a necessary pre-requisite of designing an effective test that
will tell you that.
function doStuff( errorHandler ) {
}
When will errorHandler be invoked? Maybe never, right?
That would depend on your testing. Including an error handler and then
not testing whether it handled the errors correctly would seem reckless
to me.
Or maybe it will be invoked some time after deployment, maybe
even after I'm gone from the job. Wow, that would suck.
So you would write code for a job and then walk away without testing
that it worked as designed?
Wouldn't it make sense to check the errorHandler 'thing' and
make sure it's actually a function first?
function doStuff( errorHandler ) {
if(typeof errorHandler != "function") "
var err = new Error("hey stoopid...");
log(err);
throw err;
...
}
Not as much sense as deliberately provoking the error in testing and so
knowing that it did work.
<snip>
Richard.