473,324 Members | 2,473 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,324 software developers and data experts.

Robust isArray() ?

I'm seeking the most robust and backwards-compatible (ie, no instanceof)
isArray function.

Here's what I have:

function defined(o) {
return typeof(o)!="undefined";
}
function isArray(o) {
// If these conditions aren't met, it certainly isn't an Array
if (o==null || typeof(o)!="object" || typeof(o.length)!="number") {
return false;
}
// Check to see if the object is an instance of the window's Array object
if (defined(Array) && defined(o.constructor) && o.constructor==Array) {
return true;
}
// It might be an array defined from another window object - check to see
if it has an Array's methods
if (typeof(o.join)=="function" && typeof(o.sort)=="function" &&
typeof(o.reverse)=="function") {
return true;
}
// As a last resort, let's see if index [0] is defined
return (o.length==0 || defined(o[0]));
};

Suggestions?

--
Matt Kruse
http://www.JavascriptToolbox.com
http://www.AjaxToolbox.com
Dec 14 '06 #1
33 10469

Matt Kruse wrote:

[snip]
// It might be an array defined from another window object - check to see
if it has an Array's methods
if (typeof(o.join)=="function" && typeof(o.sort)=="function" &&
typeof(o.reverse)=="function") {
return true;
}
[/snip]

Could you could do a toString instead on the constructor, and check
that?
// As a last resort, let's see if index [0] is defined
return (o.length==0 || defined(o[0]));
};
Would that catch NodeLists and HTMLCollections?

I.e. are you looking for objects that are genuine JavaScript "Arrays"
or objects which have a certain minimum interface, like "length" and
"[]" index access.

I note also that "arguments" in IE has "Object" as its constructor, but
"Array" in Opera or Firefox I think.

Regards

Dec 14 '06 #2
Julian Turner wrote:
Could you could do a toString instead on the constructor, and check
that?
I don't think so, because that can vary between browsers and doesn't return
just a single string like "Array".
> // As a last resort, let's see if index [0] is defined
return (o.length==0 || defined(o[0]));
};
Would that catch NodeLists and HTMLCollections?
Yup.
I.e. are you looking for objects that are genuine JavaScript "Arrays"
or objects which have a certain minimum interface, like "length" and
"[]" index access.
The latter. Something that must (or can) be iterated over, rather than
interacted with directly.
I note also that "arguments" in IE has "Object" as its constructor,
but "Array" in Opera or Firefox I think.
The provided functions works in both cases.

I guess one thing I'm also looking for is something that is most certainly
NOT an array, but returns true with the provided function. Then, depending
on if the test case is practical or not, I can re-think it. I don't think a
perfect solution exists.

--
Matt Kruse
http://www.JavascriptToolbox.com
http://www.AjaxToolbox.com
Dec 14 '06 #3
In comp.lang.javascript message <el*********@news4.newsguy.com>, Thu, 14
Dec 2006 11:03:11, Matt Kruse <ne********@mattkruse.comwrote:
...
// As a last resort, let's see if index [0] is defined
return (o.length==0 || defined(o[0]));
If something with contents matching those of o = [,1] can get that
far, the code will return false in IE6.

But, on the principle of Feature Detection, rather than trying to see
what it "*is*", should one not be testing whether it will *do* what one
wants it to do? If there is, for example, no intention of using its
(possible) .Sort method, then there should be no need to test for .sort
- unless one believes in the Shibboleth Method.
--
(c) John Stockton, Surrey, UK. ?@merlyn.demon.co.uk DOS 3.3, 6.20; WinXP.
Web <URL:http://www.merlyn.demon.co.uk/- FAQqish topics, acronyms & links.
PAS EXE TXT ZIP via <URL:http://www.merlyn.demon.co.uk/programs/00index.htm>
My DOS <URL:http://www.merlyn.demon.co.uk/batfiles.htm- also batprogs.htm.
Dec 14 '06 #4
Matt Kruse wrote:
I'm seeking the most robust and backwards-compatible (ie, no instanceof)
isArray function.
How backwards do you have to go? JavaScript 1.0 didn't have arrays at all.

function isArray(v) {
return v && typeof v === 'object' && typeof v.length === 'number' &&
!(v.propertyIsEnumerable('length'));
}

It thinks that the arguments object is an array (which it ought to be (but isn't)).

http://javascript.crockford.com/
Dec 15 '06 #5
Dr J R Stockton wrote:
>// As a last resort, let's see if index [0] is defined
return (o.length==0 || defined(o[0]));
If something with contents matching those of o = [,1] can get that
far...
It wouldn't.
But, on the principle of Feature Detection, rather than trying to see
what it "*is*", should one not be testing whether it will *do* what
one wants it to do? If there is, for example, no intention of using
its (possible) .Sort method, then there should be no need to test for
.sort - unless one believes in the Shibboleth Method.
Please do tell how you would "feature detect" whether an object can be
enumerated over using numeric indexes?

I don't see any fool-proof way to do it, thereby requiring a more complex
isArray function and inferring features rather than detecting them.

--
Matt Kruse
http://www.JavascriptToolbox.com
http://www.AjaxToolbox.com
Dec 15 '06 #6
Douglas Crockford wrote:
How backwards do you have to go? JavaScript 1.0 didn't have arrays at
all.
Then it would be hard to detect them ;)
function isArray(v) {
return v && typeof v === 'object' && typeof v.length === 'number'
&& !(v.propertyIsEnumerable('length'));
}
How compatible is propertyIsEnumerable?
It thinks that the arguments object is an array (which it ought to be
(but isn't)).
It behaves like one, so IMO it should return true.

--
Matt Kruse
http://www.JavascriptToolbox.com
http://www.AjaxToolbox.com
Dec 15 '06 #7
Matt Kruse said the following on 12/14/2006 12:03 PM:
I'm seeking the most robust and backwards-compatible (ie, no instanceof)
isArray function.

Here's what I have:

function defined(o) {
return typeof(o)!="undefined";
}
function isArray(o) {
// If these conditions aren't met, it certainly isn't an Array
if (o==null || typeof(o)!="object" || typeof(o.length)!="number") {
return false;
}
// Check to see if the object is an instance of the window's Array object
if (defined(Array) && defined(o.constructor) && o.constructor==Array) {
return true;
}
// It might be an array defined from another window object - check to see
if it has an Array's methods
if (typeof(o.join)=="function" && typeof(o.sort)=="function" &&
typeof(o.reverse)=="function") {
return true;
}
// As a last resort, let's see if index [0] is defined
return (o.length==0 || defined(o[0]));
};

Suggestions?
var myArray = new Array();
myArray[0] = "Its an array";
myArray[1] = "It really is an array!";
alert(isArray('myArray'))

IE7: false
Opera 9: false
Firefox 2.0: false

--
Randy
Chance Favors The Prepared Mind
comp.lang.javascript FAQ - http://jibbering.com/faq
Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/
Dec 15 '06 #8
Randy Webb said the following on 12/14/2006 11:05 PM:
Matt Kruse said the following on 12/14/2006 12:03 PM:
>I'm seeking the most robust and backwards-compatible (ie, no
instanceof) isArray function.

Here's what I have:

function defined(o) {
return typeof(o)!="undefined";
}
function isArray(o) {
// If these conditions aren't met, it certainly isn't an Array
if (o==null || typeof(o)!="object" || typeof(o.length)!="number") {
return false;
}
// Check to see if the object is an instance of the window's Array
object
if (defined(Array) && defined(o.constructor) && o.constructor==Array) {
return true;
}
// It might be an array defined from another window object - check to
see if it has an Array's methods
if (typeof(o.join)=="function" && typeof(o.sort)=="function" &&
typeof(o.reverse)=="function") {
return true;
}
// As a last resort, let's see if index [0] is defined
return (o.length==0 || defined(o[0]));
};

Suggestions?

var myArray = new Array();
myArray[0] = "Its an array";
myArray[1] = "It really is an array!";
alert(isArray('myArray'))

IE7: false
Opera 9: false
Firefox 2.0: false
And now I know why after giving it some thought and thinking about it. I
passed the name of the array rather than the array itself. Might be
something to think about though. The possibility of passing the name
instead of the array itself.

--
Randy
Chance Favors The Prepared Mind
comp.lang.javascript FAQ - http://jibbering.com/faq
Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/
Dec 15 '06 #9

Matt Kruse wrote:
Julian Turner wrote:
Could you could do a toString instead on the constructor, and check
that?

I don't think so, because that can vary between browsers and doesn't return
just a single string like "Array".
I take your point. I think it has been noted before that the results
of toString are implementation independent. However, as you are
testing for a positive, it could be another String to the bow (if you
will pardon the pun!).
[snip]
I note also that "arguments" in IE has "Object" as its constructor,
but "Array" in Opera or Firefox I think.

The provided functions works in both cases.
Yes, it would, as you are testing for length etc.
I guess one thing I'm also looking for is something that is most certainly
NOT an array, but returns true with the provided function. Then, depending
on if the test case is practical or not, I can re-think it. I don't think a
perfect solution exists.
Hmm, what about this.

function falseArray()
{
this.length = 1;
this[0] = "False first element";
}

Can't think when you would encounter this though.

Regards

Julian

Dec 15 '06 #10
VK
Matt Kruse wrote:
I'm seeking the most robust and backwards-compatible (ie, no instanceof)
isArray function.
This sentence contains two mutually exclusive demands, because the most
robust and backwards-compatible way is (someObj instanceof Array) //
true / false

So the max you can ask is "let lesser robust and lesser
backwards-compatible but without instanceof" and this pretty much
renders the problem from a practical task into a mind game.

Also from the posted sample it is hard to say what are you looking for:

1) to determine if some object has JavaScript Array object in its
prototype chain (thus inherits the functionality of JavaScript Array).

2) to determine if some object implementing JavaScript Array
functionality by its own custom means.

3) to determine if some object has properties with the same names and
types as an Array instance would have (so for some reason assumed to
have the same functionality).

Whatever the real purpose is, the posted code accomplishes (up to some
extend) only the position (3).

///////////////

Check for the position (1)
To determine if some object has JavaScript Array object in its
prototype chain (thus inherits the functionality of JavaScript Array).

JavaScript implements the prototype-based inheritance. The prototype
chain for each new instance is being activated at the moment of
creation ("new SomeObject" call) and it is only side-connected (or more
often not connected at all) to the involved function-constructors. This
way [constructor] property check is irrelevant to the prototype matter.
I'm really disappointed to see *such* [constructor] usage in *your*
code. Once again I suggest to everyone willing to understand the
JavaScript object model to read and to study the article at
<http://blogs.msdn.com/ericlippert/archive/2003/11/06/53352.aspx>

The created prototype chain is immutable and it is the only robust and
natural way to check the object kind in JavaScript.

Note:
On Netscape and Gecko platforms it is possible to hack the chain using
the proprietary __proto__ property. It means then that someone is
actively preventing the object's determination by a 3rd party. Despite
technically possible, it is supported only on a relatively small amount
of UAs and it is more related with some "conspiracy theory" than with
any practical programming. At least it has no practical interest to me.

The obvious and natural way to check the prototype chain against some
known object is instanceof operator. It was specially made for it, so
there is absolutely no reason to substitute it with any home-made
tools.

instanceof operator is supported at least back to JavaScript 1.2
(Netscape 4.x) and JScript 5.0 (IE 5.0). This way I don't understand
what "backwards-compatible" issues could it possibly raise.

At the same time I know that there is some "opposition" to instanceof
usage in JavaScript. It is caused by the fact that some class-based
languages do have instanceof operator as well, so using instanceof in
JavaScript considered by some as "betraying the prototype environment"
:-). This is a silly allusion because instanceof in JavaScript and say
instanceof in Java share nothing but their names.

instanceof in JavaScript is in fact a "syntactic sugar" for
obj.prototype.isPrototypeOf(instance)

Note:
It is not in a connection with the topic, but as long as we started on
instanceof operator:
With its real mechanics revealed as
obj.prototype.isPrototypeOf(instance) it becomes clear why each
instance is also instanceof Object
ArrayObject instanceof Array; // true
ArrayObject instanceof Object; // true as well
The latter is true because any object has Object prototype in its
chain, so all objects could share the same basic Object functionality.
People who are not aware about the inheritance principles are getting
confused sometimes by this pseudo-"double nature" of JavaScript
objects. Some of them even consider it as some "failure" of instanceof
operator (to a great fun of anyone reading such statements).

To sum the things up, instanceof operator is the only one really
reliable object check tool specially made for it. It must be always
used - unless for pure sport one wants to support very ancient and not
used anymore platforms.
///////////////
Check for the position (2)
To determine if some object implementing JavaScript Array functionality
by its own custom means.

This is the most simple one: there cannot be such JavaScript object, so
there is no need for such check.

Note:
There can be DOM object with such functionality if it has the needed
behavior/binding attached.

While the answer itself is very simple, the question of why such object
is not possible may need some more explanations.

There are "fields" and "compound properties". A field is what it names
implies - a primitive data field one can set, get and (if allowed)
delete.
var obj = new Object;
obj.foo = 'bar';
Property "foo" in the sample above is a field.

Besides that there are compound property with getter and setter. The
core difference between compound property and field is that the value
itself stored internally as a separate private variable. The only way
to change it is by using getter and setter methods.
var arr = new Array(1,2,3);
window.alert(arr.length);
arr.length = 1;
In the sample above length is a compound property. By reading/assigning
its value we are really calling getter and setter methods, the value
itself is not directly accessible. Because any call to a compound
property goes only through a method, such properties have one very
important advantage over fields:

Compound properties allow to establish relations of any complexity
between property change / read actions and other methods and
properties. Say an assignment to the array length (thus usage of length
property setter) trigs the array elements removal if the new length is
smaller than the old one.

Now how is it all connected to a possible Array mimicking? The deal is
that the [length] is the *only one* compound property existing in the
basic JavaScript, everything else are fields.

Note:
Not all of authors do always understand the unique status of [length]
as the only one compound property in the entire language. They still
feel that there is "something" about [length] making it different from
say obj.foo. But because of lack of knowledge they limit the
explanations by "special property", "self-updating property" and the
like.

Moreover basic JavaScript does *not* allow to create new compound
properties. The [length] is only one and there cannot be any others
(again: in the basic scripting environment).

Now it becomes clear why there cannot be any "self-made" arrays:
because there is no way to implement the [length] property. You either
use *that* Array, or you have to use custom length() method instead of
length property.

This makes possible to implement a tedious "arrayness" check like:
function isArray(obj) {
var ret = false;
if (typeof obj.length == 'number') {
var len = obj.length;
obj[len] = 'probe';
ret = (len < obj.length);
delete obj[len];
}
return ret;
}
There is only one object in JavaScript physically ever capable to pass
the above check (where setting one property automatically reflected in
another property). This object will be either an array instance or an
object instance having Array.prototype somewhere in its prototype
chain.

At the same time I want to stress once again that this *tedious* and
*ridiculous* isArray check is not needed. JavaScript has specially made
instanceof operator for that. It also means that there is no need for
any custom functions like isArray(), isDate(), isRegExp() at all - if
(obj instanceof Something) does all of it.

It is possible of course to make a function like
function isArray(obj) {
return (obj instanceof Array);
}
and then later:
if (isArray(obj)) {
// make stuff
}
but it's getting too much similar to the infamous Java's trutherizer
:-), so I'm insistently discouraging anyone to go this way.

Note:
About the trutherizer (sadly enough based on a real life case) see for
instance
<http://mindprod.com/jgloss/unmainobfuscation.html>, sample 34
Actually the whole page as well as the whole section
<http://www.mindprod.com/jgloss/unmain.htmlis a must-read for any
programmer, irrelevant of that programming language is being used.

To make a long story shorter: the only practical check in array could
be for the presence of particular methods.

Note:
It does not affect your particular case, but it has to be kept in mind.
While Gecko-based and many other browsers report type of native methods
as "function", Internet Explorer reports type of native methods for
JScript objects as "function" but type of native methods for DOM
objects as "object". Say typeof arrayObject.push will be "function" but
document.createElement will be "object" on IE. As I said it doesn't
affect you code but it has to be always kept in mind to avoid wrong
negatives.

So:
1) there is no need for isArray method in JavaScript unless you need to
obfuscate your code. Simply check
if (someObject instanceof Array) {
// needed actions
}
2) There can be a need to check for a particular method support, but
naturally it has to go in the head section for the Array prototype
itself.
function prepareEnvironment() {
if (typeof Array.prototype.push != 'function') {
Array.prototype.push = myCustomMethod;
}
// other preparative actions
}

Dec 15 '06 #11
VK said the following on 12/15/2006 11:39 AM:
Matt Kruse 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.

--
Randy
Chance Favors The Prepared Mind
comp.lang.javascript FAQ - http://jibbering.com/faq
Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/
Dec 15 '06 #12
VK
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"

Dec 15 '06 #13
VK

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"
OK, if we want a IE 4.x or Netscape 3.x compatible solution, that the
"most robust" way will be the one with [length] autoupdate check (see
my first post in this thread).
But as I pointed in advance, it is a concept demonstration, so I'm
strictly opposed to see this code practically used anywhere, instead of
the conventional instanceof operator.

Dec 15 '06 #14
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 I can see where you might be tempted to apply some
JRS logic to the statement. It is a combined requirement, not exclusive
requirements.

--
Randy
Chance Favors The Prepared Mind
comp.lang.javascript FAQ - http://jibbering.com/faq
Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/
Dec 16 '06 #15
VK wrote:
Matt Kruse wrote:
>I'm seeking the most robust and backwards-compatible
(ie, no instanceof) isArray function.

This sentence contains two mutually exclusive demands,
No it does not. "Most robust" is a relative term and
"backward-compatible" is a condition inside which relative robustness is
to be judged. It may be that given "backward-compatible" the most
relative robustness that can be achieved is not very robust at all, but
there will still be a "most robust".
because the
most robust and backwards-compatible way is (someObj
instanceof Array) // true / false
If true that would be a pity as (someObj instanceof Array) is true for
an entire category of objects that are not arrays and cannot be treated
as arrays. That is, anything created with a constructor that has an
Array as its prototype or an object as a prototype that has an Array on
its prototype chain. Such objects would not have any special interest in
the assignment of 'array index' or "length" properties, and so would not
exhibit the Array-ness that is most likely the characteristic that needs
to be identified by the proposed function.
So the max you can ask is "let lesser robust and lesser
backwards-compatible but without instanceof"
Matt's English is much better than that, and there was nothing wrong
with the question as expressed, beyond its failure to explain what the
proposed - isArray - function was specifically intended to do.
and this pretty much renders the problem from a
practical task into a mind game.
Not rally, an actual specification for the function should reduce the
answer to a specific "it cannot be done" or code that does it one step.
Also from the posted sample it is hard to say what are
you looking for:
It is, but even harder for you as you have never really grasped what a
javascript array actually is.
1) to determine if some object has JavaScript Array
object in its prototype chain (thus inherits the
functionality of JavaScript Array).
The functionality of a javascript array cannot be inherited, only the
methods.
2) to determine if some object implementing JavaScript
Array functionality by its own custom means.
No javascript object can do that, only host objects.
3) to determine if some object has properties with the
same names and types as an Array instance would have
(so for some reason assumed to have the same functionality).
No such assumption is valid as any object inheriting from an array will
have all the properties of an array but will not be an array itself.
Whatever the real purpose is, the posted code accomplishes
(up to some extend) only the position (3).

///////////////

Check for the position (1)
To determine if some object has JavaScript Array object in
its prototype chain (thus inherits the functionality of
JavaScript Array).

JavaScript implements the prototype-based inheritance.
The prototype chain for each new instance is being
activated
Assigned
at
After.
the moment of creation
- of the instance of a new native ECMAScript object.
("new SomeObject" call)
The application of the - new - operator to a function reference starts a
process with at least two distinct stages so is better not though of a
'moment of creation', rather a process of creation where a certain
amount of important work (such as the creation of the actual object and
assignment of the prototype chain) precedes the execution of the
constructor function's body code.
and it is only side-connected (or more often not
connected at all) to the involved function-constructors.
It is actually very important to a constructor that the new object's
prototype chain has been established before the constructor body code is
executed. It allows a constructor to call the methods of the new object
as they have been defaulted on the object's prototype chain.
This way [constructor] property check is
irrelevant to the prototype matter. I'm really disappointed
to see *such* [constructor] usage in *your* code.
It is only not-valid to reject all objects that do not have an Array
constructor as their - constructor - property as being Arrays in a world
where programmers are insane enough to re-assign values to -
Array.prototype.constructor - or assign - constructor - properties to
Array instances. Programmers who know that they are doing will just not
do that, but I can see why that test may concern you.
Once again I suggest to everyone willing to understand
the JavaScript object model to read and to study the
article at
<http://blogs.msdn.com/ericlippert/archive/2003/11/06/53352.aspx>
Advice on the understanding of javascript is not credible when it
originates from someone who so self evidently does not understand
javascript himself:-

<URL:
http://groups.google.com/group/comp...._frm/thread/64
ae20ba5c760c6/2820fbcd4b4ab7f8 >
The created prototype chain is immutable and it is the
only robust and natural way to check the object kind
in JavaScript.
Knowing that another object is on the prototype chain of another object
is nowhere near sufficient in answering the question of identifying
objects that are Arrays and excluding objects that are not. You may be
able to dismiss all objects that do not have - Array.protoype - on their
prototype chain but you cannot then assume that the non-excluded set are
Arrays.

<snip>
The obvious and natural way to check the prototype chain
against some known object is instanceof operator. It was
specially made for it, so there is absolutely no reason
to substitute it with any home-made tools.
Beyond its inability to answer the pertinent question.
instanceof operator is supported at least back to
JavaScript 1.2 (Netscape 4.x)
This would be "supported at least back to JavaScript 1.2" in the sense
of 'introduced in JavaScript 1.4 and first available in Netscape 6+and
Mozilla 0.9'.
and JScript 5.0 (IE 5.0). This way I don't understand
what "backwards-compatible" issues could it possibly
raise.
Not knowing when and where language features were introduced can make
seeing back-compatibility issues harder to spot.
At the same time I know that there is some "opposition"
to instanceof usage in JavaScript.
Such as observing that it is not very back-compatible and not necessary
at all and not very useful.
It is caused by the fact that some class-based
languages do have instanceof operator as well, so
using instanceof in JavaScript considered by some
as "betraying the prototype environment"
Nonsense.
:-). This is a silly allusion because instanceof
in JavaScript and say instanceof in Java share
nothing but their names.
And - instanceof - is very useful in Java, particularly as it allows
code to verify the safety of something like casting to an interface. In
javascript there is no casting, being an instance of a 'class' that
implements an interface does not guarantee the ability to use that
interface on the object and runtime assignments to the - prototype -
properties of constructors can throw the - - instanceof - operator off,
i.e:-

function AnObject(){
;
}

var obj = new AnObject();
AnObject.prototype = {};

alert((obj instanceof AnObject)); // alerts false;

- so an object that is constricted with the right hand operand of -
instanceof - might still return false form that operation.
instanceof in JavaScript is in fact a "syntactic sugar" for
obj.prototype.isPrototypeOf(instance)
And the same issue with the runtime assignment to the constructor's
prototype applies here.
Note:
It is not in a connection with the topic, but as long as we
started on instanceof operator:
With its real mechanics revealed as
obj.prototype.isPrototypeOf(instance)
That is not its real mechanics, that is an alternative that employs an
almost identical algorithm.
it becomes clear why each
instance is also instanceof Object
ArrayObject instanceof Array; // true
ArrayObject instanceof Object; // true as well
The latter is true because any object has Object prototype
in its chain, so all objects could share the same basic
Object functionality. People who are not aware about the
inheritance principles are getting confused sometimes by
this
It was certainly a subject that was confusing you just two months ago
when you wrote:-

<URL:
http://groups.google.co.uk/group/com...c44f32b4566384
53 >

- but since I explained it to you there you seem to have started to
grasp prototype based inheritance. Though you still have some way to go.
I would anticipate another two years before you rid yourself of your
remaining misconceptions on the subject and get a real handle on the
issue (base on your not having got it after your first ten years of
using javascript).
pseudo-"double nature" of JavaScript objects.
It would speed your gaining an understanding of javascript is you would
refrain form making up your own jargon. It just leaves you talking a
different language from everyone else, and that will make understanding
what you are told difficult.
Some of them even consider it as some "failure" of
instanceof operator (to a great fun of anyone reading
such statements).
You realise that most of the time what you perceive as the attitudes of
others are in fact just the consequences of your not understanding what
you are being told by the better informed. I have never seen any
evidence of anyone (at all) expressing this belief. And that is often a
common thread in your posts, where you start going on about how people
are concerned with this or that when in reality nobody is even
interested in whatever it is you are whittering on about. A case in
point is in:-

<URL:
http://groups.google.co.uk/group/com...3bc6c90a43d991
0f >

- where you start going on about:-

| This is the point where different amateurish manuals starting
| to advise do not use unary minus: which is a 100% pure b.s. of
| course because at no circumstances the program *logic* can be
| affected by external textual parser.

- in the context of using the pre-decrement operator (not unary minus)
with script code inside <!-- ... --comments in an XML file. This
impression of yours is a complete fantasy of your own creation because
in XML comments may be stripped from the source prior to parsing, and so
nobody is ever going to wrap them round content that is supposed to be
data, and doing so would effectively remove the data from the XML. There
is not, and never has been (outside of your own head), any issue with
using pre/post decrement operators in that context because that context
is itself a fiction.
To sum the things up, instanceof operator is the only
one really reliable object check tool specially made
for it.
Or it is a non-back-compatible operator that may be able to exclude
objects that could not be Arrays but cannot in itself verify that any
given object is an Array.
It must be always used
It is inadequate for the task in hand. And you yourself pointed out
that - isPrototypeOf - can produce equivalent results (so "must be used"
is false anyway), but while you cannot feature test for support for an
operator in the language you can feature test for a method of objects.
- unless for pure sport one wants to support very ancient
and not used anymore platforms.

///////////////
Check for the position (2)
To determine if some object implementing JavaScript Array
functionality by its own custom means.

This is the most simple one: there cannot be such JavaScript
object, so there is no need for such check.
In the same way as your preceding option could not exist in javascript
(Array functionality cannot be inherited).
Note:
There can be DOM object with such functionality if it has
the needed behavior/binding attached.
There can also be host object with the Array functionality (and language
extensions).
While the answer itself is very simple, the question
of why such object is not possible may need some more
explanations.
It is fairly simple to explain, and follows from the inability of client
side code to replace the object's internal [[Put]] method. While it
would be theoretically possible to use the - watch - or -
__defineSetter__ - extensions in JavaScript(tm) to reproduce the side
effects of assignments to all possible 'array index' properties and
the - length - property of an object (and so fully reproduce the
behaviour required of the internal [[Put]] method on a custom object the
very large number of possible 'array index' properties that would need
to be watched would make the creation of such an object very time
consuming and probably a practical impossibility due to restrictions in
available memory.
There are "fields" and "compound properties".
Ah, you are going to do one of your infamous 'off the top of your head'
fantasies.
A field is what it names implies - a primitive data field
one can set, get and (if allowed) delete.
var obj = new Object;
obj.foo = 'bar';
Property "foo" in the sample above is a field.

Besides that there are compound property with getter and setter.
The core difference between compound property and field is that
the value itself stored internally as a separate private
variable. The only way to change it is by using getter and
setter methods.
var arr = new Array(1,2,3);
window.alert(arr.length);
arr.length = 1;
In the sample above length is a compound property. By
reading/assigning its value we are really calling getter
and setter methods, the value itself is not directly
accessible. Because any call to a compound property goes
only through a method, such properties have one very
important advantage over fields:

Compound properties allow to establish relations of any
complexity between property change / read actions and other
methods and properties. Say an assignment to the array
length (thus usage of length property setter) trigs the
array elements removal if the new length is smaller than
the old one.
A side effect following from an assignment to a named property.
Now how is it all connected to a possible Array mimicking?
Oh, do tell.
The deal is that the [length] is the *only one* compound
property existing in the basic JavaScript, everything else
are fields.
The only one? So no assignment to any other property will ever have a
side effect on a property that is not the subject of the assignment?
That would be an inevitable consequence of the mechanism you are
describing where the only " compound property" in the entire system was
the - length - property of array objects.
Note:
Not all of authors do always understand the unique status of
[length]
Here you go again, attributing beliefs to others where no evidence
exists that anyone has these beliefs.
as the only one compound property in the entire language.
You said it again " one compound property in the entire language", so
defiantly no other assignments will have side effects, no matter what.
They still feel that there is "something" about [length]
making it different from say obj.foo. But because of lack of
knowledge they limit the explanations by "special property",
"self-updating property" and the like.
Who does this? The informed attribute all special array behaviour
relating to assignment to the special internal [[Put]] method of arrays.
Moreover basic JavaScript does *not* allow to create new
compound properties. The [length] is only one and there
cannot be any others
That is three times, we can be very certain that the varsity of this
'explanation' is tied 100% to the 'fact' that assignment operations to
any other property of any object in the system can have a side effect on
another property. There is no question that this a matter of
interpretation, a mistranslation, or a misquote; if any other assignment
can be demonstrated as having a side-effect in standard javascript this
entire 'explanation' is just false (that it is the 'off the top of your
head' fantasy that I suspected from the outset).
(again: in the basic scripting environment).
Fine.
Now it becomes clear why there cannot be any "self-made"
arrays: because there is no way to implement the [length]
property.
Well, with the - watch - extension it would be entirely possible to
implement an array-like length property, Granted that is not in the
basic scripting language, but it does raise a significant objection to
your 'explanation' above, because while it would be trivial to implement
an array like - length - property on any object with the - watch -
method (explicitly script the side effects of assignments to the length
property) it would still not be practical to implement an array like
object with the - watch - method.

The problem is that that is not just one property that may have side
effect when an assignment is made, each array has (2 to the power of 32)
such properties. An assignment to any 'array index' property, where the
index is grater than or equal to, the length property will have a side
effect on the - length - property, it will increase it. It is the
impracticality of using the - watch - method to trigger any possible
side-effect for each such assignment that precludes an emulation of an
array with other object.

However, your explanation of a single "compound property" is not only
failing to explain these other side-effect producing assignments, but
also suffers from the same practical limitation, as if a property
specific setter is the means of producing the side effect your
explanation needs (2 to the power of 32) additional setters, and that is
going to be impractical even in native code.

The explanation if much simpler; it is that all javascript objects have
an internal [[Put]] method that is used for assignments, that this
method is passed the property name and the value that is to be assigned,
and that Arrays have a single special [[Put]] method that examines the
property name to see if it is an array index property name or "length"
and if it is performs the appropriate side-effect on the Array object to
which the [[Put]] method belongs. That is how the language specification
say javascript should behave, and is sufficient to fully explain the
behaviour observed.
You either use *that* Array, or you have to use custom
length() method instead of length property.

This makes possible to implement a tedious "arrayness"
check like:
function isArray(obj) {
var ret = false;
if (typeof obj.length == 'number') {
var len = obj.length;
obj[len] = 'probe';
Isn't this 'test' predicated on the fact that assigning to an 'array
index' property of an Array does produce a side-effect on its - length -
property? Where you not just 'explaining' how that was not possible in
javascript because the 'array index' properties are not your "compound
properties"? While I don't expect someone as irrational as you to
produce internally consistent posts you could at least make an effort
not to obviously contradict yourself.
ret = (len < obj.length);
delete obj[len];
}
return ret;
}
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).
There is only one object in JavaScript physically ever
capable to pass the above check
(where setting one property automatically
reflected in another property).
Weren't you saying that only assignments to the - length - property has
such side effects? While this property has a name that is the
type-converted to string equivalent of the value of the - length -
property.
This object will be either an array instance
Or a host object with array-like behaviour.
or an object instance having Array.prototype somewhere
in its prototype chain.
Nonsense. Having an array in an object's prototype chain does not confer
this "side-effect on assignment to 'array index' properties" on such an
object, because the internal [[Put]] method is a property of each
individual object and cannot be inherited. Any object that inherits from
an Array can still only have the standard object [[Put]] method, which
does not do side effects when used.
At the same time I want to stress once again that this
*tedious* and *ridiculous* isArray check is not needed.

Not that test, but a better implementation of a similar test (that does
not leave the objects tested altered by the testing) would be the only
type of testing that would be capable of identifying objects which
behaved as if they had the special Array [[Put]] method.

function isArray(obj){
var len, res = false;
if(
(typeof (len = obj.length) == 'number')&&
((len >>0) == len)&&
(typeof obj[len] == 'undefined')
){
obj[len] = null;
res = (obj.length (obj.length = len));
delete obj[len];
}
return res;
}

- would be better, but still suffers from potentially moving an
inherited - length - property form the prototype of a non-array object
onto the object itself.
JavaScript has specially
made instanceof operator for that.
Having made the mistake of thinking that array-ness could be inherited
through the protyo00e chain you might think that.
It also means that there is no need for any custom
functions like isArray(), isDate(), isRegExp() at
all - if (obj instanceof Something) does all of it.
So maybe it is a pity that it does none of it.

<snip>
To make a long story shorter: the only practical check
in array could be for the presence of particular methods.
<snip>

This would be "practical" in the sense of not ending up knowing whether
the object in question was an array or not (very similar to using
instanceof in that regard).

Richard.
Dec 16 '06 #16
Richard Cornford said the following on 12/16/2006 1:40 AM:
VK wrote:
>Matt Kruse wrote:
>>I'm seeking the most robust and backwards-compatible
(ie, no instanceof) isArray function.
<snip>
Matt's English is much better than that, and there was nothing wrong
with the question as expressed, beyond its failure to explain what the
proposed - isArray - function was specifically intended to do.
The intent, to me, was very apparent in that the function is
specifically intended to determine if an object is an array or not and
do it in the most robust way possible while retaining as much backwards
compatibility as possible.

Or, do you expect to get a dissertation from anyone asking a question?

--
Randy
Chance Favors The Prepared Mind
comp.lang.javascript FAQ - http://jibbering.com/faq
Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/
Dec 16 '06 #17
Randy Webb wrote:
Richard Cornford said the following on 12/16/2006 1:40 AM:
>VK wrote:
>>Matt Kruse wrote:
I'm seeking the most robust and backwards-compatible
(ie, no instanceof) isArray function.

<snip>
>Matt's English is much better than that, and there was nothing
wrong with the question as expressed, beyond its failure to
explain what the proposed - isArray - function was specifically
intended to do.

The intent, to me, was very apparent in that the function is
specifically intended to determine if an object is an array or not
<snip>

That was my impression too, but there was no specification of what being
an array means in this context. And that question is rendered more
unclear by Matt's subsequent suggestion that - arguments - objects
should be included (even though it does not have the methods or an
array, the special [[Put]] method and assignments to 'array index'
properties of an - arguments - object are specified as having side
effects on named properties of the Activation/Variable object for which
it is the - arguments - value).

Richard.

Dec 16 '06 #18

Matt Kruse schrieb:
I'm seeking the most robust and backwards-compatible (ie, no instanceof)
isArray function.

Here's what I have:

function defined(o) {
return typeof(o)!="undefined";
}
function isArray(o) {
// If these conditions aren't met, it certainly isn't an Array
if (o==null || typeof(o)!="object" || typeof(o.length)!="number") {
return false;
}
// Check to see if the object is an instance of the window's Array object
if (defined(Array) && defined(o.constructor) && o.constructor==Array) {
return true;
}
// It might be an array defined from another window object - check to see
if it has an Array's methods
if (typeof(o.join)=="function" && typeof(o.sort)=="function" &&
typeof(o.reverse)=="function") {
return true;
}
// As a last resort, let's see if index [0] is defined
return (o.length==0 || defined(o[0]));
};

Suggestions?

--
Matt Kruse
http://www.JavascriptToolbox.com
http://www.AjaxToolbox.com
I am impressed by your discussion, but what I am using and what is
working an all current browsers is:

isArray = function(object) {
return object instanceof Array;
};

Dec 16 '06 #19

webEater schrieb:
Matt Kruse schrieb:
I'm seeking the most robust and backwards-compatible (ie, no instanceof)
isArray function.

Here's what I have:

function defined(o) {
return typeof(o)!="undefined";
}
function isArray(o) {
// If these conditions aren't met, it certainly isn't an Array
if (o==null || typeof(o)!="object" || typeof(o.length)!="number") {
return false;
}
// Check to see if the object is an instance of the window's Array object
if (defined(Array) && defined(o.constructor) && o.constructor==Array) {
return true;
}
// It might be an array defined from another window object - check to see
if it has an Array's methods
if (typeof(o.join)=="function" && typeof(o.sort)=="function" &&
typeof(o.reverse)=="function") {
return true;
}
// As a last resort, let's see if index [0] is defined
return (o.length==0 || defined(o[0]));
};

Suggestions?

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

I am impressed by your discussion, but what I am using and what is
working an all current browsers is:

isArray = function(object) {
return object instanceof Array;
};
I mean IE 5.5+, Opera 7+, Mozilla, FF 1+, Safari 1/2, ..

Dec 16 '06 #20
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/
Dec 16 '06 #21
VK
- 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.

:-D
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) {
...
}

Dec 16 '06 #22
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.
Dec 16 '06 #23
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.
Dec 16 '06 #24
In comp.lang.javascript message <V5********************@telcove.net>,
Fri, 15 Dec 2006 22:53:05, Randy Webb <Hi************@aol.comwrote:
>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.htmjscr maths, dates, sources.
<URL:http://www.merlyn.demon.co.uk/TP/BP/Delphi/jscr/&c, FAQ items, links.
Dec 17 '06 #25
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
Dec 17 '06 #26
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/
Dec 17 '06 #27
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.
Dec 17 '06 #28
VK

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.

Dec 18 '06 #29
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.
Dec 18 '06 #30
Matt Kruse wrote:
I'm seeking the most robust and backwards-compatible (ie, no instanceof)
isArray function.

Here's what I have:

function defined(o) {
return typeof(o)!="undefined";
}
function isArray(o) {
// If these conditions aren't met, it certainly isn't an Array
if (o==null || typeof(o)!="object" || typeof(o.length)!="number") {
return false;
}
// Check to see if the object is an instance of the window's Array object
if (defined(Array) && defined(o.constructor) && o.constructor==Array) {
return true;
}
// It might be an array defined from another window object - check to see
if it has an Array's methods
if (typeof(o.join)=="function" && typeof(o.sort)=="function" &&
typeof(o.reverse)=="function") {
return true;
}
// As a last resort, let's see if index [0] is defined
return (o.length==0 || defined(o[0]));
};

Suggestions?
If by "array" you mean something that can be iterated over with the
following construct:

for(var index = 0; index < myArray.length; index++)
alert(myArray[index]);

without error, then any object that has a non-negative numeric 'length'
property will satisfy your criteria.

As for your last test:
return (o.length==0 || defined(o[0]));

Consider the following:

var x = new Array();
x[5] = "garbanzo";
alert(typeof n[0]); //"undefined" in FF 1.5

I would instead check whether o[o.length - 1] is defined - if it's not,
then o has no reason to have length of o.length (however there is
nothing preventing you from explicitly setting the length of the array).

In the above example:

var x = new Array();
x[5] = "garbanzo";
alert(typeof n[n.length - 1]); //"string"

Jeremy

Dec 19 '06 #31
Jeremy wrote:
If by "array" you mean something that can be iterated over with the
following construct:
for(var index = 0; index < myArray.length; index++)
alert(myArray[index]);
without error, then any object that has a non-negative numeric
'length' property will satisfy your criteria.
I suppose, but that doesn't mean that numeric indexes from 0..(length-1) of
the object are intended to hold any meaningful data.
As for your last test:
return (o.length==0 || defined(o[0]));
Consider the following:
var x = new Array();
x[5] = "garbanzo";
alert(typeof n[0]); //"undefined" in FF 1.5
That's why this case would already be trapped by the code about the final
test.
I would instead check whether o[o.length - 1] is defined - if it's
not, then o has no reason to have length of o.length
This might be logically true, but one could easily do:

var empty = [,,,,,];

--
Matt Kruse
http://www.JavascriptToolbox.com
http://www.AjaxToolbox.com
Dec 19 '06 #32
VK

Richard Cornford wrote:
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.
Hum... indeed. That's kind of a silly behavior I did not notice before
- as I never used delete on array elements. IMO delete should work the
same way as delete someObject.someProperty - not keeping someProperty
with undefined value but _delete_ it as it never existed.
Well, it's easy to fix:

function isArray(obj) {
var ret = false;
var len = 0;

if (obj) {
len = parseInt(obj.length, 10);
if (len == len) {
obj[len] = 'probe';
ret = (len < obj.length);
obj.length = len;
}
}

return ret;
}

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;
What browser did you test it on? Of course it fails (false). As I said,
there is no technical way to implement compound property within
ECMAScript 3rd ed. It's not a teasing for an intellectual challenge,
just a constatation of a fact. Respectively this isArray is absolutely
rubust yet absolutely not needed with instanceof alive.

Dec 22 '06 #33
VK wrote:
Richard Cornford wrote:
>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.

Hum... indeed. That's kind of a silly behavior I did not
notice before - as I never used delete on array elements.
And you only needed to be told why your original - isArray - function
was inadequate three times before you tried it for yourself.
IMO delete should work the same way as delete
someObject.someProperty - not keeping someProperty
with undefined value but _delete_ it as it never existed.
That is exactly what - delete - does do. I don't know what exactly
passes as testing with you but it doesn't appear to leave yo0u any
better informed.
Well, it's easy to fix:

function isArray(obj) {
var ret = false;
var len = 0;

if (obj) {
len = parseInt(obj.length, 10);
if (len == len) {
obj[len] = 'probe';
ret = (len < obj.length);
obj.length = len;
}
}

return ret;
}
You really don't understand what the code you write does, and even when
your faults are pointed out you just don't know how to correct them. You
have change code that modifies the - length - property of all the arrays
that are exposed to it into code that adds a new (or changes an
existing) property to (on) every non-array object it encounters that has
a numeric - length - property (which, at minimum, includes all String
and Function objects, plus many custom objects). A test function really
should not permanently modify the objects that it tests.
>>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;

What browser did you test it on?
Firefox, Opera and IE (though it is pure ECMAScript so would be expected
to work with all anyway). Why didn't you test it? Or why couldn't you
manage to perform such a simple test effectively?
Of course it fails (false).
When the - isArray - function is the function that you posted and
declared "absolutely robust", that was:-

| 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;
| }

- the result is exactly as I described; the alert is 'isArray(obj) =
true'. You could verify that by trying it yourself, as anyone else can.
As I said, there is no technical way to implement
compound property within ECMAScript 3rd ed.
As your whole "compound property" thing was a fiction with no reality
outside your own head anything you say on the subject is irrelevant.
It's not a teasing for an intellectual challenge,
just a constatation of a fact.
It is a fiction.
Respectively this isArray
"This isArray"? Not the previous one?
is absolutely rubust
So there can be no object for which - isArray(obj) - (where - isArray -
is your new version rather than the previous version that reported -
true - for the object I already posted) returns true?

One of the consequences of your basing your conception of javascript on
your ludicrous fictions is that you end up making statements that are
easily demonstrated as false. This object:-

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

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

- returns - true - from your newest "absolutely robust" array test, even
though it is clearly not an array. It does so for precisely the same
reason as my previous object returned true from your previous -
isArray - test. And if you had bothered to test my previous object with
your previous test you may have seen the obvious truth that would have
suggested that you not label this test as any more "absolutely robust"
as your last easily fooled test.
yet absolutely not needed with instanceof alive.
If you had understood my criticism of your use of - instanceof - in this
context you would be able to see why that would not help anyway.

Richard.
Dec 22 '06 #34

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

11
by: Laphan | last post by:
Hi All I'm using .getRows() with a local var array instead of doing a recursive loop so that I'm being a good ASP newvbie and closing my object i/o's (the recordset in this case) as quick as...
8
by: =?ISO-8859-1?Q?Norbert_P=FCrringer?= | last post by:
Hello again, I've got a type variable, e.g. Type type; Now I want to know whether the type represents an Array type (System.Array). type.IsArray results false because System.Array is an...
18
by: Aaron Gray | last post by:
I know this has probably been argued to death, but I am going to raise it fresh again, and basically lets have an unofficial 'isArray()' contest that we can hopefully put it to rest as best as we...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
1
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
1
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.