Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Javascript > Robust isArray() ?

Reply
Thread Tools

Robust isArray() ?

 
 
Douglas Crockford
Guest
Posts: n/a
 
      12-16-2006
> What I am using and what is
> working an all current browsers is:
>
> isArray = function(object) {
> return object instanceof Array;
> };


This fails if the array is constructed in a different frame.
Some might say that is not robust.

http://javascript.crockford.com/
 
Reply With Quote
 
 
 
 
VK
Guest
Posts: n/a
 
      12-16-2006
- I'm seeking the most robust and backwards-compatible
(ie, no instanceof) isArray function.

- This sentence contains two mutually exclusive demands

- No it doesn't.

- Cheking my math :
1) "most robust"
2) "no instanceof"

> As I know from reading 14 kazillion of your posts that English is not
> your primary language I can see where you might be tempted to apply some
> JRS logic to the statement.


AFAIK JRS is pretty much fluent in English. He has some troubles in
expressing clearly his thoughts - but he has a grammar and a
vocabulary, which is as good as anyone could get in his remote location
(with the explainable excuse for a funny orthography). This way
bringing JRS as a sample is questionable.



> It is a combined requirement, not exclusive
> requirements.


First of all it is a provocative requirement. One think is to ask "How
to access controls in my form?" and another - for instance - to ask
"How to implement inheritance w/o that stupid prototype?"

The OP's question was of the second kind, so getting back not only an
actual technical answer but some theoretical explanations of his
mistakes as well should not surprise him.

For me the requirements of a kind "I want to go to the left and stay on
the same place", "I want to use native JavaScript inheritance mechanics
but without using prototype", "I want a robust way to determine
instance type but without using instanceof" - for me all these
requirements are *mutually exclusive requirements*. If you consider
them as *combined requirements* thus logically merging into one valid
achievable task, then of course it is your right to think so.

P.S. In my original post I mentioned a check based on the array
specifics. There is no way to cheat on it within the standard
JavaScript/JScript environment - no matter how experienced the
programmer is. It can be even further adjusted to accommodate Netscape
3.x as well (so bye-bye typeof operator):

function isArray(obj) {
var ret = false;
if ((obj) && (!(isNaN(parseInt(obj.length))))) {
var len = parseInt(obj.length, 10);
if (len == obj.length) {
obj[len] = 'probe';
ret = (len < obj.length);
delete obj[len];
}
}
return ret;
}

This code as absolutely robust (there is no way to cheat on it),
backward-compatible back to Netscape 2.0 and obviously goes beyond the
borders of any sanity at the current time. From the other side at the
older times c.l.j. used to solve the "practical sanity" of problems by
simply making up an imaginary browser with any features missing in any
needed combinations - so to create then imaginary problems for that
imaginary browser and then victoriously overcome them by making crazy
code chunks like the one above. (The leftovers of this approach are
still remaining in the "window size" FAQ).

So one may consider this code as my personal handful of sand on this
practice. Welcome to the 21st century:

if (someObject instanceof Array) {
...
}

 
Reply With Quote
 
 
 
 
Richard Cornford
Guest
Posts: n/a
 
      12-16-2006
VK wrote:
> - I'm seeking the most robust and backwards-compatible
> (ie, no instanceof) isArray function.
>
> - This sentence contains two mutually exclusive demands
>
> - No it doesn't.
>
> - Cheking my math :
> 1) "most robust"
> 2) "no instanceof"

<snip>
>> It is a combined requirement, not exclusive
>> requirements.

<snip>
> ... . If you consider them as *combined requirements*
> thus logically merging into one valid achievable task,
> then of course it is your right to think so.


It is everyone's right to understand the language they use.

> P.S. In my original post I mentioned a check based on
> the array specifics.


A rather poor example as it modified all the arrays that were exposed to
it.

> There is no way to cheat on it within the standard
> JavaScript/JScript environment - no matter how
> experienced the programmer is.


It would certainly be possible to create an object in JavaScript(tm)
that would pass this test without being an Array.

> It can be even further adjusted to accommodate Netscape
> 3.x as well (so bye-bye typeof operator):


Rather pointless as isNaN became generally available in JavaScript 1.1,
which also introduced typeof.

> function isArray(obj) {
> var ret = false;
> if ((obj) && (!(isNaN(parseInt(obj.length))))) {
> var len = parseInt(obj.length, 10);
> if (len == obj.length) {
> obj[len] = 'probe';
> ret = (len < obj.length);
> delete obj[len];
> }
> }
> return ret;
> }
>
> This code as absolutely robust


But a very poor test as it still modifies all arrays passed to it, and
may modify other objects it sees. A test that significantly changes the
objects it acts upon is not at all a good test. Any change would be
undesirable but adding one to the length of each and every array has got
to be an unacceptable consequence for any test of whether an object is
an array.

<snip>
> So one may consider this code as my personal handful of
> sand on this practice. Welcome to the 21st century:
>
> if (someObject instanceof Array) {
> ...
> }


function AnObject(){
;
}
AnObject.prototype = [];

var obj = new AnObject();

alert((obj instanceof Array)); //alerts true
alert(isArray(obj)); //alerts false

So your - instanceof - test says this object is an array, and the -
isArray - function that above you described as reliable and impossible
to fool says that it is not an array. You may think of the 21st century
as a time for writing faulty scripts because of personal ignorance of
the behaviour of the code you are writing (and only being told that it
doesn't work a couple of times), others are free to disagree.

Richard.


 
Reply With Quote
 
Richard Cornford
Guest
Posts: n/a
 
      12-16-2006
VK wrote:
<snip>
> function isArray(obj) {
> var ret = false;
> if ((obj) && (!(isNaN(parseInt(obj.length))))) {
> var len = parseInt(obj.length, 10);
> if (len == obj.length) {
> obj[len] = 'probe';
> ret = (len < obj.length);
> delete obj[len];
> }
> }
> return ret;
> }
>
> This code as absolutely robust (there is no way to
> cheat on it),

<snip>

So this object cannot fool your - isArray - test:-

function AnObject(){
;
}
AnObject.prototype = {
length:{
count:0,
valueOf:function(){
return this.count++;
},
toString:function(){
return '0';
}
}
};
var obj = new AnObject();

alert(('isArray(obj) = '+isArray(obj)));//alerts isArray(obj) = true;

-? (using - typeof - should seem like a better idea now as it would not
have been so easily fooled)

Richard.


 
Reply With Quote
 
Dr J R Stockton
Guest
Posts: n/a
 
      12-16-2006
In comp.lang.javascript message <>,
Fri, 15 Dec 2006 22:53:05, Randy Webb <> wrote:
>VK said the following on 12/15/2006 12:11 PM:
>>>>> I'm seeking the most robust and backwards-compatible (ie, no instanceof)
>>>>> isArray function.
>>>> This sentence contains two mutually exclusive demands
>>> No it doesn't.

>> Cheking my math :
>> 1) "most robust"
>> 2) "no instanceof"

>
>As I know from reading 14 kazillion of your posts that English is not
>your primary language


Agreed. I have always considered him to be an American immigrant of the
first or second generation.

> I can see where you might be tempted to apply some JRS logic to the
>statement. It is a combined requirement, not exclusive requirements.


It is ambiguous, to those who understand how English should be written.

The "most robust and backwards-compatible" could be intended to mean
((most robust) and (backwards-compatible)) - that's a rational
requirement, if and only if (backwards-compatible) is of Boolean nature.

The use of "ie" (which should be "i.e.", standing for /id est/) in
principle implies that "no instanceof" is a necessary and sufficient
condition for code to be backwards-compatible (clearly it is necessary;
but is it sufficient? I doubt that). However, ISTM bold to presume that
the author was aware when writing of the distinction between "i.e." and
"e.g." (standing for /exempli gratia/); if "e.g." should have been used,
then "no instanceof" is not necessarily deemed a sufficient condition.

It could be intended to mean ((most robust) and (most
backwards-compatible)) - and, unless it is possible to be ((completely
robust) or (completely backwards-compatible)), that is an undecidable
condition unless there are agreed or stated scales of merit for those
two properties so that for any proposed solution a total figure of merit
can be assessed.


Of course, using "most" is only appropriate for properties measurable
(in principle) on a scale, which is hardly the case here. So "...
seeking a robust and backwards-compatible ..." must be the real intent.

--
(c) John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v6.05 IE 6
<URL:http://www.jibbering.com/faq/> A FAQ for news:comp.lang.javascript.
<URL:http://www.merlyn.demon.co.uk/js-index.htm> jscr maths, dates, sources.
<URL:http://www.merlyn.demon.co.uk/> TP/BP/Delphi/jscr/&c, FAQ items, links.
 
Reply With Quote
 
Matt Kruse
Guest
Posts: n/a
 
      12-17-2006
Richard Cornford wrote:
> That was my impression too, but there was no specification of what
> being an array means in this context.


I clarified a bit, but I was also hoping to get some opinions about what
people think should happen with such a function.

> And that question is rendered
> more unclear by Matt's subsequent suggestion that - arguments -
> objects should be included


My thought was that anything that behaves like an array should be considered
an array. Thinking of when the function would be used helps to determine how
it should behave.

For example: document.forms["name"].elements["firstname"]

Such a function could be used to figure out if this is a collection of
elements or a single element. Since the collection wouldn't be an instanceof
Array, yet still behaves as expected in a for() loop to iterate over the
results, I would expect isArray to return true.

--
Matt Kruse
http://www.JavascriptToolbox.com
http://www.AjaxToolbox.com


 
Reply With Quote
 
Randy Webb
Guest
Posts: n/a
 
      12-17-2006
Matt Kruse said the following on 12/16/2006 7:51 PM:
> Richard Cornford wrote:
>> That was my impression too, but there was no specification of what
>> being an array means in this context.

>
> I clarified a bit, but I was also hoping to get some opinions about what
> people think should happen with such a function.


My original thought was that you wanted to test an object to see if it
was an Array or not. The only thing I noted was that you have to pass
the array itself and it failed if you gave it only the name of the array.

>> And that question is rendered
>> more unclear by Matt's subsequent suggestion that - arguments -
>> objects should be included

>
> My thought was that anything that behaves like an array should be considered
> an array.


A better name for the function would be isCollection if you just want
Objects that can be iterated over like an Array but doesn't have to
specifically be an Array.

> Thinking of when the function would be used helps to determine how
> it should behave.
>
> For example: document.forms["name"].elements["firstname"]
>
> Such a function could be used to figure out if this is a collection of
> elements or a single element. Since the collection wouldn't be an instanceof
> Array, yet still behaves as expected in a for() loop to iterate over the
> results, I would expect isArray to return true.


isCollection would be a better name

I think your goal is to broad to do in a simple single test though.
There are different collections that require different tests and you
would have to test for every single possible collection/array
possibility to be able to return true on them all.

--
Randy
Chance Favors The Prepared Mind
comp.lang.javascript FAQ - http://jibbering.com/faq
Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/
 
Reply With Quote
 
Richard Cornford
Guest
Posts: n/a
 
      12-17-2006
Matt Kruse wrote:
> Richard Cornford wrote:
>> That was my impression too, but there was no specification
>> of what being an array means in this context.

>
> I clarified a bit, but I was also hoping to get some opinions
> about what people think should happen with such a function.


It always has been, and remains, my opinion that a test procedure should
be determined by what you want to know from the test. That is, the
answer starts with deciding what the test function is for, and how it is
going to be used.

If you call a function - isArray - then I would expect it to reject
things that are not arrays and make a positive assertion about all
javascript arrays and anything that was indistinguishable from an array.
But the thing that most stands out as defining array-ness in javascript
is that assigning to an 'array index' property may change the - length -
property and assigning to the length property may change a number of
'array index' properties. The challenge would then be to test that
(which implies attempting modifications to the object) without leaving
the subjects of the test modified in any way. Extra tests for the
methods of an Array may allow the exclusion of many non-array objects
prior to attempting modifications.

Such a test would not categorise NodeLists, Collections or arguments
objects as arrays.

>> And that question is rendered more unclear by Matt's
>> subsequent suggestion that - arguments - objects should
>> be included

>
> My thought was that anything that behaves like an array
> should be considered an array.


And the arguments object does not behave like an Array.

Thinking about this it occurs to me that I have never verified how well
implementations handle the requirement that changing the value of an
'array index' member of the - arguments - object should have the side
effect of changing the value of corresponding named properties of the
Activation/Variable object (and vice versa), but as you can pass an
arguments object to another function there should be some interesting
cross-closure communication possibilities in that relationship if it is
reliable.

> Thinking of when the function would be used
> helps to determine how it should behave.
>
> For example: document.forms["name"].elements["firstname"]
>
> Such a function could be used to figure out if this is a
> collection of elements or a single element.


I would have considered that a case where a collection specific test
would be more appropriate.

> Since the collection wouldn't be an instanceof Array,
> yet still behaves as expected in a for() loop to
> iterate over the results,


Any object with a non-negative numeric integer length property less than
or equal to (2 to the power of 53) can be iterated over with a - for -
loop, because trying to read non-existing 'index' properties would just
return the Undefined value, as would happen with a sparse array. That is
a fairly easy test applied only to the - length - property; numeric type
and acceptable range. (All functions would pass such a test).

> I would expect isArray to return true.


I would not call a function making such a test - isArray -.

Richard.


 
Reply With Quote
 
VK
Guest
Posts: n/a
 
      12-18-2006

Richard Cornford wrote:
> A rather poor example as it modified all the arrays that were exposed to
> it.


? What do you think is [delete] operator for? To beautify the code?

> It would certainly be possible to create an object in JavaScript(tm)
> that would pass this test without being an Array.


It is possible over JScript behavior or JavaScript binding (Gecko) -
but I already meantioned it in my original post. It is absolutely not
possible within the frame of ECMAScript 3rd ed.

> isNaN became generally available in JavaScript 1.1,
> which also introduced typeof.


Can very well be true: everything before Netscape 3.0 is getting really
foggy now in my memory.

 
Reply With Quote
 
Richard Cornford
Guest
Posts: n/a
 
      12-18-2006
VK wrote:
> Richard Cornford wrote:
>> VK wrote:
>> A rather poor example as it modified all the arrays that
>> were exposed to it.

>
> ? What do you think is [delete] operator for? To beautify
> the code?


What did you understand me to mean when I wrote:-

| Any test that is intended to differentiate between objects
| that are arrays and objects that are not arrays should not
| be designed to permanently alter the object that is tested.
| Here any array that passes the test will find itself with a
^^^^^^^^^^^^^^^^^^
| - length - property that is one longer than it was to start
^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| with, which is pretty important given what an array is.
^^^^
| (All javascript objects, including arrays, use the same
^^^^^^^^
| internal [[Delete]] method, and it has no side-effects).
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^

-? Especially the words "All javascript objects, including arrays, use
the same internal [[Delete]] method, and it has no side-effects". You
have added one to the length of every array. That is the basis of the
test, but deleting the 'array index' member you have added to the array
does not have any side-effects on the array's - length - property so it
remains one greater then it was to start with.

Given that you don't understand the code you write you really should try
reading the actual wording of the corrections you are given and trying
to understand them. I should not need to state your fault three times
before you see it for yourself. (assuming you can see it now)

>> It would certainly be possible to create an object in
>> JavaScript(tm) that would pass this test without being an Array.

>
> It is possible over JScript behavior or JavaScript binding
> (Gecko) - but I already meantioned it in my original post.
> It is absolutely not possible within the frame of ECMAScript
> 3rd ed.


Didn't you see my other reply to that test code with the standard
javascript object that fools your " absolutely robust" into believing it
is an array without its even inheriting the methods or an array? I
suppose I had better post it again for your benefit:-

function AnObject(){
;
}
AnObject.prototype = {
length:{
count:0,
valueOf:function(){
return this.count++;
},
toString:function(){
return '0';
}
}
};
var obj = new AnObject();

alert(('isArray(obj) = '+isArray(obj)));//alerts isArray(obj) = true;

That object will fool the test code you posed and it is noting but ECMA
262, 3rd Ed. conforming code.

>> isNaN became generally available in JavaScript 1.1,
>> which also introduced typeof.

>
> Can very well be true: everything before Netscape 3.0 is
> getting really foggy now in my memory.
>
>>> function isArray(obj) {
>>> var ret = false;
>>> if ((obj) && (!(isNaN(parseInt(obj.length))))) {
>>> var len = parseInt(obj.length, 10);
>>> if (len == obj.length) {
>>> obj[len] = 'probe';
>>> ret = (len < obj.length);
>>> delete obj[len];
>>> }
>>> }
>>> return ret;
>>> }
>>>
>>> This code as absolutely robust


Richard.


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Robust CSS dorayme HTML 10 06-20-2006 10:47 PM
robust iterator implementation Martin Smith C++ 4 01-25-2005 11:12 AM
robust clean-up with SIGTERM (was Re: Again, how to write a cleanup function for a module in C ) Jane Austine Python 2 08-16-2003 04:01 AM
ANN: EmPy 3.0.4 -- A powerful and robust templating system for Python Erik Max Francis Python 0 08-08-2003 03:53 AM
ANN: EmPy 3.0.3 -- A powerful and robust templating system for Python Erik Max Francis Python 0 07-09-2003 10:11 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57