Why do prototyped methods of Array show up as members in individual arrays?
Here's some code to demonstrate how I came across this problem:
Code:
//prototype a custom method to Array
Array.prototype.something = function()
{
};
//prototype a method which is native
//to all test browsers except IE5.0
Array.prototype.push = function()
{
};
//data is a non-associative array
var data = [];
//therefore it has no length property
//so to find its length we have to iterate like this
var dataLen = 0;
for(var i in data) { dataLen++; }
//tell us the length of the array
alert(dataLen);
We get 1 in all browsers except for IE5.0, which returns 2. The differences makes sense, because both methods are custom to IE5.0, whereas push() is already native to the others.
The question is - why do prototyped methods show up at all, when native methods do not?
__________________
"Why bother with accessibility? ... Because deep down you know that the web is attractive to people who aren't exactly like you." - Joe Clark
Last edited by brothercake; 12-20-2004 at 10:46 AM..
My bad - what I mean is, an array which is indexed with string keys
__________________
"Why bother with accessibility? ... Because deep down you know that the web is attractive to people who aren't exactly like you." - Joe Clark
The reason is that host methods in general are defined to not be enumerable, while all native methods are. That is in effect for the entire prototype chain, not just the object the method is placed upon. The member lookup scheme is indifferent to whether it's looking at direct members of the object or whether it's looking at prototype members. That way there is no need for building separate internal lookup methods for the two cases - there is only one case, in which you search an object for a member and if not finding it starting the same process with the next object in the prototype chain.
Also, all arrays have length, whether you use them as associative arrays or not. It's only objects, which can be used as hashtables/associative arrays if you wish, that do not have a length. Whether you use string keys or not is irrelevant. This can easily be shown by doing the following:
Code:
var
o=[true];
o['0']=false;
alert(o[0]); // => false
The reason is that all lookups in JavaScript are by string keys, and if you don't use a string it will be converted to a string before doing the lookup.
Also, all arrays have length, whether you use them as associative arrays or not. .
They don't have a length property ...
Code:
var data = [];
data['foo'] = 'bar';
alert(data.length); //alerts 0
__________________
"Why bother with accessibility? ... Because deep down you know that the web is attractive to people who aren't exactly like you." - Joe Clark
Perfect example, exactly the opposite conclusion to what I would have drawn from it. If it didn't have a length property it would have returned undefined.
Quote:
Code:
var data = [];
data['foo'] = 'bar';
alert(data.length); //alerts 0
Object properties and array elements are fundamentally different. (Well, not in implementation but in how it looks from an outside perspective.) Adding an object property to an array naturally doesn't increment the length of the array, because you have not added an array element. Array elements are a subset of object properties on Array type objects, namely those object properties that have a numeric index. You cannot access object properties on an array using numeric index, so it makes no sense to add them to the length - that would break any looping through the array if you allowed it. JavaScript doesn't have any native Collection/Dictionary object (which is just that - a hashtable were all hashes are also accessible by numeric index), so if that's the feature you're looking for, you'll have to write the object for it yourself.
What I really need is to be able to go "for(i in myarray)" and be confident that prototyped methods of Array which [may] exist in other [unknown] scripting are not included. But I can acheive that by checking each iteration with typeof, or further testing it as necessary, to determine if it's a member I'm interested in.
Thanks for your help, as ever
__________________
"Why bother with accessibility? ... Because deep down you know that the web is attractive to people who aren't exactly like you." - Joe Clark
Last edited by brothercake; 12-21-2004 at 11:08 PM..
But then discovered that I couldn't simply walk the attributes of a generic object without bumping into my own function identifiers. To prevent that, I found that if I test a given attribute against an empty object, then I can determine which are pre-existing attributes and which are not...
Code:
$=function(x,json){
var elem=document.getElementById(x);
if(json)for(a in json)if(!{}[a])elem[a]=json[a];
return elem
};
_=function(x,json){
var elem=document.createElement(x);
if(json)for(a in json)if(!{}[a])elem[a]=json[a];
return elem
};
BTW: I use my $ function for manipulation of existing DOM objects and the _ function for creating new DOM objects. By passing a JSON (JavaScript Object Notation) parameter, I can very easily assign attributes and attach event handlers.
Code:
$('someElementID',
{'color':'red',
'onblur':function(){('ERROR: Invalid '+this.id+' value ['+this.value+']').alert();this.focus()}
}
);
Last edited by ca_redwards; 06-08-2006 at 12:59 AM..