Its the isArray() function thing again

A

Aaron Gray

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 can.

I have found things that work perfectly well as long as you don't try them
on MSIE, ie adding Object and Array prototype isArray functions, thus :-

Object.prototype.isArray = function() { return false }
Array.prototype.isArray = function() { return true }

This falls down on builtin browser types in IE, so is no good.

The one version that I have seen is :-

function isArray( a) { return typeof a.push == "function" }

Prototype for all its "failings" extends object and provides :-

Object.extend(Object, {
isArray: function(object) {
return object != null && typeof object == "object" &&
'splice' in object && 'join' in object;
}
});

So checking of non null and splice and join maybe better than just checking
for push.

So something like :-

function isArray( o) { return o != null && typeof o == "object" &&
'push' in o }

But I am not sure when 'in' was actually introduced.

function isArray( o) { return o != null && typeof o == "object" &&
typeof o.push == "function" }

Would probably do best/better. This is what I have settled on for now.

Then there was the advice to use === rather than ==, but I dont know when
that was introduced too, or whether it is really necessary as == works just
as well AFAICS.

Any critisisms, advances, or advice ?

Aaron
 
P

Peter Michaux

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 can.

In your actual application code, why are you ever having any trouble
knowing if a variable references an Array or not? If a function's API
states it should recieve an array argument, then just send it an array
argument. If it states it should receive a number, don't send it an
array. Be careful about bringing the baggage of focusing on type
checking and casting from languages like Java or C++ to your
JavaScript programming.
I have found things that work perfectly well as long as you don't try them
on MSIE, ie adding Object and Array prototype isArray functions, thus :-

Object.prototype.isArray = function() { return false }
Array.prototype.isArray = function() { return true }

Augmenting built in prototypes with generic names like "isArray" is
likely to collide in an envronment where multiple authors are writing
the JavaScript.

http://peter.michaux.ca/article/7979

This falls down on builtin browser types in IE, so is no good.

The one version that I have seen is :-

function isArray( a) { return typeof a.push == "function" }

That is a very wimpy test in general.

Prototype for all its "failings" extends object and provides :-

The quotation marks are not necessary.

Object.extend(Object, {
isArray: function(object) {
return object != null && typeof object == "object" &&
'splice' in object && 'join' in object;
}
});

Why they think writing

Object.isArray

is any different than

PrototypeJS.isArray

I will never understand.

So checking of non null and splice and join maybe better than just checking
for push.

So something like :-

function isArray( o) { return o != null && typeof o == "object" &&
'push' in o }

But I am not sure when 'in' was actually introduced.

function isArray( o) { return o != null && typeof o == "object" &&
typeof o.push == "function" }

So if I define a new object in JavaScript with a push function it will
pass your test. That is a very weak test.

Would probably do best/better. This is what I have settled on for now.

Then there was the advice to use === rather than ==, but I dont know when
that was introduced too,
http://pointedears.de/scripts/es-matrix/


or whether it is really necessary as == works just
as well AFAICS.

They are not the same. == and != do type coercion.

http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Operators:Comparison_Operators

Any critisisms, advances, or advice ?

What's wrong with

if (obj instanceof Array) {
// do stuff
}

http://developer.mozilla.org/en/doc...erators:Special_Operators:instanceof_Operator

Peter
 
L

Lasse Reichstein Nielsen

Aaron Gray said:
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 can.

Is there a setting where

obj instanceof Array

fails to detect an Array?

....
Prototype for all its "failings" extends object

That's one failing right there :)
I thought they stopped doing that in later versions?
and provides :-

Object.extend(Object, {
isArray: function(object) {
return object != null && typeof object == "object" &&
'splice' in object && 'join' in object;

Sigh. Feature detection is good for detecting features. This is detection
by inference. This is as bad as
var isIE = document.all ? 1 : 0;
(ok, slightly better, the isIE example has more bad points than it has
keywords)
So checking of non null and splice and join maybe better than just checking
for push.

"maybe" is the operative word. I.e., it's shooting blind and hoping to
be lucky.
So something like :-

function isArray( o) { return o != null && typeof o == "object" &&
'push' in o }

But I am not sure when 'in' was actually introduced.

JScript 5.6
JavaScript 1.4

Same versions as "instanceof", btw.
function isArray( o) { return o != null && typeof o == "object" &&
typeof o.push == "function" }

Would probably do best/better. This is what I have settled on for now.

And when we implement a stack:

function Stack() {}
Stack.prototype.push = function(o) {
this.head = {elem: o, next: this.head }
};
Stack.prototype.pop = function() {
var head = this.head;
if (head) {
var elem = head.elem;
this.head = head.next;
return elem;
}
};

it suddently qualifies as an array?

An object is an Array if it inherits Array.prototype. That's the
prototype based definition of inheritance.
Then there was the advice to use === rather than ==, but I dont know when
that was introduced too, or whether it is really necessary as == works just
as well AFAICS.

It's the same when dealing with objects. The "==" operator performs
type conversion in some cases, whereas the "===" requires both
operands to have the same type. When the operands are objects, they
work exactly the same,
Any critisisms, advances, or advice ?

What problem are you trying to solve?
Why?


In any case, don't try to be clever. Either use "instanceof", or, if
it's *really* necessary to support ancient browsers, test simple
things:

function isArray(o) {
return o && o.constructor == Array;
}

It's easy to cheat, but anybody actively trying to cheat is going to
succeede anyway.

/L
 
G

Gregor Kofler

Aaron Gray meinte:
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 can.

Crockford suggests

var is_array = function(v) {
return v && typeof v === "object" && v.constructor === Array;
}

(wont work on arrays in other windows/frames)

or

var is_array = function(v) {
return v && typeof v === "object" && typeof v.length === "number" &&
typeof v.splice === "function" && !(v.propertyIsEnumerable("length"));
}

(I suppose he took splice() because it's a relatively "rare" method)

Gregor
 
A

Aaron Gray

Lasse Reichstein Nielsen said:
Is there a setting where

obj instanceof Array

fails to detect an Array?

Don't know. But I had forgotten about 'instanceof Array' and thats exactly
what I need for this specific problem.

I think people use the other 'weaker' methods to allow inclusion of array
like objects as well as Arrays.
In any case, don't try to be clever. Either use "instanceof", or, if
it's *really* necessary to support ancient browsers, test simple
things:

function isArray(o) {
return o && o.constructor == Array;
}

Thomas is right, I really should read ECMA-262 properly.

Many thanks,

Aaron
 
D

dhtml

Is there a setting where

  obj instanceof Array

fails to detect an Array?

There is: When obj is an Array in a different frame than the Array
constructor, it would be constructed via a different Array
constructor, and so obj instanceof Array would have to be false.
otherFrame.obj instanceof otherFrame.Array would be true, though.


That was quite a long time ago.
That's one failing right there :)
I thought they stopped doing that in later versions?

Yes, they did.

Garrett
 
P

Peter Michaux

That was quite a long time ago.

They are still extending "Object" unnecessarily with function-valued
properties that could be added to any object. Adding them to "Object"
is just confusing, in my opinion. They also choose very generic names
in shared namespaces which is another problem of theirs.

http://www.prototypejs.org/api/object

Peter
 
R

RobG

There is: When obj is an Array in a different frame than the Array
constructor, it would be constructed via a different Array
constructor, and so obj instanceof Array would have to be false.
otherFrame.obj instanceof otherFrame.Array would be true, though.


That was quite a long time ago.


Yes, they did.

They stopped extending Object.prototype.
 
D

dhtml

They stopped extending Object.prototype.

Ah, right that's what I was thinking about. Modifying
Object.prototype. That was very bad.

They still extend Object, which is not as bad. They add a clone()
method to Object, and clone is an ES3.1 Proposal. I asked Allen about
that

Object.clone is proposed for ES 3.1. I did mention it on the list, but
Allen was replying to a lot of responders, so he probably missed what
I wrote:

| It seems like Object.clone might create compatibility with existing
| code. There is already a widespread use of an Object.clone on the
web.


Garrett
 
P

Peter Michaux

:

[snip]
[snip]
[snip]

They still extend Object, which is not as bad. They add a clone()
method to Object, and clone is an ES3.1 Proposal. I asked Allen about
that

Object.clone is proposed for ES 3.1. I did mention it on the list, but
Allen was replying to a lot of responders, so he probably missed what

Who is "Allen"?
I wrote:

| It seems like Object.clone might create compatibility with existing
| code. There is already a widespread use of an Object.clone on the
web.

"compatibility" or "incompatibility" with Prototype.js' Object.clone?
It looks to me like there will be incompatibility as Prototype.js'
Object.clone is a shallow copy and the ES3.1 Object.clone is a much
deeper clone of an Object. This is why adding generically named
properties in shared namespaces is a problem. The Prototype.js
developers have been burned by this at least a few times in the past
two years. That may imply they have influence over the evolution of
JavaScript and the DOM. Unfortunately it also means they are causing
unnecessary maintenance headaches for Prototype.js users.

Peter
 
J

Jorge

Allen Wirfs-Brock,http://preview.tinyurl.com/5hf4na

There is little point in posting tinyurl URLs as nobody in their right
mind would follow one, just as nobody in their right mind would follow a
URL found in a spam post.

Not even if it points to a preview, like that one ?
We Mac users aren't so frightened of urls.

--Jorge.
 
R

Richard Cornford

dhtml wrote:
Object.clone is proposed for ES 3.1. I did mention it on the
list, but Allen was replying to a lot of responders, so he
probably missed what I wrote:

| It seems like Object.clone might create compatibility with
| existing code. There is already a widespread use of an
| Object.clone on the web.

Assuming you mean "incompatibility" where you wrote "compatibility",
then ES 3.1 defining an - Object.clone - method is not an issue unless
it is defined as a read-only (or ES 3.1's equivalent of read-only). If a
script loads in into (and is executed in) an ES 3.1 environment and that
script assignees its own method to - Obejct.clone - then so long as that
assignment succeeds code in the same context that uses - Object.clone -
will be using the version it is expecting to use.

Richard.
 
R

Richard Cornford

Jorge said:
Not even if it points to a preview, like that one ?

How would it be possible to determine what it points to without
following it?
We Mac users aren't so frightened of urls.

It is probably best if I don't comment on that.

Richard.
 
D

dhtml

dhtml wrote:


Assuming you mean "incompatibility" where you wrote "compatibility",

I remember thinking "compatibility issue" when I was typing.
then ES 3.1 defining an - Object.clone - method is not an issue unless
it is defined as a read-only (or ES 3.1's equivalent of read-only). If a
script loads in into (and is executed in) an ES 3.1 environment and that
script assignees its own method to - Obejct.clone - then so long as that
assignment succeeds code in the same context that uses - Object.clone -
will be using the version it is expecting to use.

Where "it" is the PrototypeJS library itself.

A user of PrototypeJS would have to contend with things like:

<script>
Object.clone( o };
</script>

<script src="prototype-1.7.js"></script>

<script>
Object.clone( o };
</script>

PrototypeJS.cloneObject would be safer.

Garrett
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top