469,572 Members | 1,718 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,572 developers. It's quick & easy.

Array and Hash (Associative array) in JavaScript v.3.0

VK
Whatever you wanted to know about it but always were affraid to ask.

<http://www.geocities.com/schools_ring/ArrayAndHash.html>

Jul 28 '05 #1
35 6256
VK wrote:
Whatever you wanted to know about it but always were affraid to ask.

<http://www.geocities.com/schools_ring/ArrayAndHash.html>


I think you need to reconsider your comments about array length (my
wrapping of comments):

"var arrayObject = new Array(3); // arrayObject has 3 undefined
// elements"

That misconception has been repeated many times throughout your article.

The ECMA specification does not say that the length property is the
number of elements in the array, it is defined as being numerically
greater than the name of every property whose name is an array index
(which means it will be equal to the largest index plus 1 or greater).

For all practical purposes, it is irrelevant whether:

var x = new Array( 99 );

actually creates an array of 99 elements or not, but it does
explicitly create an array with a length property of 99. And that is
all you can say with certainty.

You appear to have disregarded the extensive conversation logged here
where the above was pointed out in great detail:

<URL:http://groups.google.com.au/group/comp.lang.javascript/browse_frm/thread/c12423afa53a28f8/589d140d9290e7a9?q=array+length+undefined&rnum=7&h l=en#589d140d9290e7a9>

Other conversations have recently covered similar ground.
An important property not mentioned by your page is that any element
with an index not less than the length will be deleted, so if you have
an array with length 10 and you set it to 1, any element with index of
1 or greater is deleted.

--
Rob
Jul 28 '05 #2
VK
> I think you need to reconsider your comments about array length (my
wrapping of comments):

"var arrayObject = new Array(3); // arrayObject has 3 undefined
// elements"

That misconception has been repeated many times throughout your article.
The misconception (or a plain stubborness) I'm trying to fight with has
been indeed discussed many times and its wrongness is demonstrated very
clearly in the article. I encourage you to go through again of:
<http://www.geocities.com/schools_ring/ArrayAndHash.html#Array_Length>
and below, as well as apply other array methods of you choice.

This misconception (let's stick to this softer term) erises from the
brute mix of the low level memory allocation and the high level
programming entity behavior.

As I may notice from your previous postings, the matrix transpoding is
your hobby(?). So especially for you it is vital to understand what are
you really working with and how will it respond to the applied methods.
The ECMA specification does not say that the length property is the
number of elements in the array, it is defined as being numerically
greater than the name of every property whose name is an array index
(which means it will be equal to the largest index plus 1 or greater).

For all practical purposes, it is irrelevant whether:

var x = new Array( 99 );

actually creates an array of 99 elements or not, but it does
explicitly create an array with a length property of 99. And that is
all you can say with certainty.

<http://www.geocities.com/schools_ring/ArrayAndHash.html#Array_Length>
and further. Read the code samples in the grayed area. *Read it* , not
just pass over as "a method implementation error".

An important property not mentioned by your page is that any element
with an index not less than the length will be deleted, so if you have
an array with length 10 and you set it to 1, any element with index of
1 or greater is deleted.

Yes, as well is if you assign arrayObject = [] then all elements will
be removed. I did not want to mention in a public reading that the
Array.length can be used as a brute force ReDim (alloc) method. What
you don't know will not hurt you :-) Array has enough methods to
accomplish it more gracefully and reliably.

Jul 28 '05 #3
Interesting Article. I have been criticized for using the array type as
a hash (sort of) in a script that I created:

Test = new function() {

var $listeners = new Array();

function _NotifyListeners($newHash) {
for (var $key in $listeners)
$listeners[$key].Update($newHash);
};

this.AddListener = function($obj) {
if (!$obj.Update) return false;
$listeners[$listeners.length] = $obj;
if ($obj.Load)
$obj.Load($currentHash);
return true;
};
this.RemoveListener = function($obj) {
for (var $key in $listeners)
if ($listeners[$key] == $obj)
delete $listeners[$key];
};

...

};
I did this because it is convenient to use for ( in ) loops, and because
it is also convenient to use the length property to create a new key to
hold the added listener.

I wonder what you think about doing something like that. Is it abuse to
use an Array in this way?

Kevin N.
Jul 28 '05 #4
VK
> NotifyListeners

Oh, I smell hot java! :-)
....
var $listeners = new Array();
function _NotifyListeners($newHash) {
for (var $key in $listeners) {
$listeners[$key].Update($newHa*sh);
}
}
....

This situation is described at:
<http://www.geocities.com/schools_ring/ArrayAndHash.html#ArrayAsHash>

Briefly *and in Java terms* you're creating an array object only to use
its super class methods and properties.
Visually it's equal to:

objectTwo = new objectOne();
and then continuosly
(objectOne)objectTwo.someMethod();
The natural question erises why did you create objectTwo on the first
place?

Or if we go back to JavaScript it's like:
var foo = false;
and few lines below:
foo = "Hello world!";

If you planned to use foo as string, why would you init it by boolean?

Is it an "abuse"? An abuse would be to use to force something to work
in the way it was not made for. So I would not say it's an "abuse".
Is it an unnecessary complication of your code readability? I would say
yes, for sure.
Is it a bad programming practice? Yes I guess.
var $listeners = {};
would make it clear and natural.

Jul 28 '05 #5
> var $listeners = {};
would make it clear and natural.


That would make more sense I guess, but it would also eliminate the
$listeners.length property (I would use $listeners.push() but I'm
targeting IE 5.0), which I use in the AddListener method. Is there some
easy way to add an anonymous property to an object? (anonymous because I
don't have a name/id for it - which is why I'm using $listeners.length
to generate one.)

Kevin N.
Jul 28 '05 #6
"VK" <sc**********@yahoo.com> writes:

Remember attribution for your quotes.
Briefly *and in Java terms* you're creating an array object only to use
its super class methods and properties.


Not really, since he also does:
$listeners[$listeners.length] = $obj;


i.e., he is using integer indices, incrementally. Not something that
couldn't be done manually, though.

/L
--
Lasse Reichstein Nielsen - lr*@hotpop.com
DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
'Faith without judgement merely degrades the spirit divine.'
Jul 28 '05 #7
Is what I've done considered hacky? It is quite convenient, but in your
opinion, should I use an integer variable that I increment manually (for
code readability)?

Kevin N.
Jul 28 '05 #8
VK
VK says:
Briefly *and in Java terms* you're creating an array object only to use
its super class methods and properties.
Lasse Reichstein Nielsen says:
Not really, since he also does:
$listeners[$listeners.length] = $obj;


This is actually where I stoke because this code should not work at
all. Unless somewhere below you do $listeners.length++ and *then* it's
an abuse. Otherwise $listeners.length is always 0.

Full code of the constructor?

Jul 28 '05 #9
VK
But overall if it works for you then fine.

Array used as Hash, Hash used as Array...

Is it correct? No. Does it work? Then leave it as it is.

Jul 28 '05 #10
I'm confused as to why that should break it (commented):

Test = new function() {

// defines as an array with .length = 0
var $listeners = new Array();

function _NotifyListeners($newHash) {
// loops through array using inherited object looping
// Does accessing in this way redefine it as an object?
for (var $key in $listeners)
$listeners[$key].Update($newHash);
};

this.AddListener = function($obj) {
if (!$obj.Update) return false;

// adds an object to the array (integer based index)
// really just emulating push(), so that it works on IE 5.0
$listeners[$listeners.length] = $obj; // still array

return true;
};
this.RemoveListener = function($obj) {
// loops through array using inherited object looping
// Does accessing in this way redefine it as an object?
for (var $key in $listeners)
if ($listeners[$key] == $obj)
delete $listeners[$key];
};

...

};
As far as I understand, it is never redefined as Object, and remains an
Array. I just use its inherited functionality from the object (since in
javascript all types inherit from Object) to iterate over it, and to
delete properties (or array elements).

I have admittedly not tested the RemoveListener method - however the
MSDN JScript reference (yeah, I know, it can't be considered the final
voice) says that using delete to remove array elements is perfectly fine
(and I have tested that on other platforms, even Netscape 4.x).

After writing all this, I guess this whole thread is off topic, since
I'm not actually using the array as a hash (I'm using integer indices).
So I apologize if this is off topic.
Jul 28 '05 #11
VK wrote:
Full code of the constructor?


Oh, do you want to see where I'm using this? I'm using it here:

http://www.unfocus.com/Projects/Hist...storyKeeper.js
Jul 28 '05 #12
On 28/07/2005 19:52, Kevin Newman wrote:
I'm confused as to why that [using the length property to simulate
the push method] should break it (commented):
VK is mistaken.

[snip]
var $listeners = new Array();
I'm curious: why are all of your identifiers prefixed by dollar symbols?
That particular character is meant for use with mechanically created
code (though that isn't enforced, of course).

[snip]
I have admittedly not tested the RemoveListener method - however the
MSDN JScript reference [...] says that using delete to remove array
elements is perfectly fine [...].
You should have no trouble using the delete operator with native
objects. However, using it with a host object in IE (such as a DOM
object) will cause an error, even if you created the property in question.
After writing all this, I guess this whole thread is off topic, since
I'm not actually using the array as a hash (I'm using integer indices).


You're not using it as a hash, as such, but you're not using it as an
array either. You're taking advantage of the fact that it increments a
value, rather than you doing it yourself.

I would (and in fact, do) use a list for similar code. Though a
comparison between the properties of sequential and linked data
structures don't really apply here (as Array objects aren't likely to be
backed by an array), there are some parallel from a design perspective.
You also need to consider duplicate element checks during insertion;
for..in statements aren't that efficient outside IE.

Finally, and I'm just being picky here, using an array in this manner is
also self-limiting (though that limit is extremely large) as, in time,
you'd run out of numbers.

Mike

--
Michael Winter
Prefix subject with [News] before replying by e-mail.
Jul 28 '05 #13
Kevin Newman wrote:
Interesting Article.
Just don't make the mistake of failing to appreciate that, like anything
written by VK, you will know less as a result of reading it that you
would have if you hadn't bothered.
I have been criticized for using the array type
as a hash (sort of) in a script that I created:

Test = new function() {

var $listeners = new Array();

function _NotifyListeners($newHash) {
for (var $key in $listeners)
$listeners[$key].Update($newHash);
};

this.AddListener = function($obj) {
if (!$obj.Update) return false;
$listeners[$listeners.length] = $obj;
In assigning a reference to an object to a member of the array using the
array's length you are using the array as an array, because you are only
assigning members that have 'array index' property names. That doesn't
appear to be necessary in this case and the real role of the array here
is that its length is effectively a self incrementing value (each new
addition of an 'array index' property of $listeners.length makes the
array one item longer), and so provides a sequence of unique property
names.

If you kept your own numeric 'length' property, and explicitly
incremented it upon assignment you could use an Object to achieve the
same effect. The only practical difference would be that the Object's
[[Put]] method is simpler (and so probably quicker) than the special
[[Put]] method used by Arrays, and you would have less need to worry
about using - for/in - and having unexpected properties enumerated (as
Objects are less likely targets for prototype extensions than Arrays).
if ($obj.Load)
$obj.Load($currentHash);
return true;
};
this.RemoveListener = function($obj) {
for (var $key in $listeners)
if ($listeners[$key] == $obj)
delete $listeners[$key];
The - delete - operator does not have any impact on the length property
of an Array, so even deleting the last 'array index' property in an
array will not decrement the length. It is a good thing that javascript
arrays are sparse as this strategy would otherwise involve an ever
expanding memory use.
};

...

};

I did this because it is convenient to use for ( in ) loops,
Which work the same for all objects (in the sense of using the same
specified algorithm, host objects do not have well defined rules as to
which properties will be enumerable).
and because it is also convenient to use the length
property to create a new key to hold the added listener.
I don't see much in it, the alternative would just be:-

Test = new function() {
var $listeners = {};
var key = 0;
...
this.AddListener = function($obj) {
if (!$obj.Update) return false;
$listeners[++key] = $obj;
if ($obj.Load)
$obj.Load($currentHash);
return true;
};
...
};

- and work the same.
I wonder what you think about doing something like that.
Is it abuse to use an Array in this way?


To avoid incrementing your own counter? It seems over the top to take on
the baggage of an array just for that feature.

Incidentally, the dollar symbol is specifically mentioned in ECMA 262
(3rd edition, section 7.6) as being intended for use only in machine
generated code, so it should probably be avoided in javascript (that is
not machine generated). And because prefixing identifiers with dollar
symbols has special meaning in some other languages their use in
javascript (where they have no special meaning beyond signifying machine
generated Identifiers) is likely to be misleading.

Richard.
Jul 28 '05 #14
Michael Winter wrote:
I'm curious: why are all of your identifiers prefixed by dollar symbols?
I used those because I intend to compress my project with Dean Edwards'
Packer script for distribution.

http://dean.edwards.name/packer/

I would (and in fact, do) use a list for similar code.
Do you have an example of what you mean by a list? I found a script that
implements CList (on mozilla.com or something), but it has a lot of code
in it, and felt like overkill for what I want to use it for.

Finally, and I'm just being picky here, using an array in this manner is
also self-limiting (though that limit is extremely large) as, in time,
you'd run out of numbers.


That's pretty picky :-) the number 15 is probably way more than should
ever be used with the script I'm using this for.
Jul 28 '05 #15
VK wrote:
I think you need to reconsider your comments about array length (my
wrapping of comments):

"var arrayObject = new Array(3); // arrayObject has 3 undefined
// elements"

That misconception has been repeated many times throughout your article.

The misconception (or a plain stubborness) I'm trying to fight with has
been indeed discussed many times and its wrongness is demonstrated very
clearly in the article.


If you are discussing your stubbornness, then yes, it is demonstrated.
I encourage you to go through again of:
<http://www.geocities.com/schools_ring/ArrayAndHash.html#Array_Length>
and below, as well as apply other array methods of you choice.
Subsequent readings have not changed the text or my understanding of it.
This misconception (let's stick to this softer term) erises from the
brute mix of the low level memory allocation and the high level
programming entity behavior.
Then it is all the more strange that you did not indicate how to get rid
of unwanted values in an array (though I note that you seem to be
working on an 'array methods' page), nor that it is likely that the
difference in the amount of memory consumed by the following arrays:

var x = new Array( 1 );
var y = new Array( 10000 );

is either zero or trivial.
As I may notice from your previous postings, the matrix transpoding is
your hobby(?). So especially for you it is vital to understand what are
you really working with and how will it respond to the applied methods.
I'm not aware of 'matrix transponding', but I'll look it up. ;-)

My interest is mostly in attempting to gain a better understand
mathematics. Implementing operations in a programming language requires
that you either learn or develop algorithms for performing those
operations - it's the next best thing to teaching.

JavaScript is a very convenient language as I can work on nearly any
platform that has a browser and text editor with almost no compatibility
issues.
The ECMA specification does not say that the length property is the
number of elements in the array, it is defined as being numerically
greater than the name of every property whose name is an array index
(which means it will be equal to the largest index plus 1 or greater).

For all practical purposes, it is irrelevant whether:

var x = new Array( 99 );

actually creates an array of 99 elements or not, but it does
explicitly create an array with a length property of 99. And that is
all you can say with certainty.


<http://www.geocities.com/schools_ring/ArrayAndHash.html#Array_Length>
and further. Read the code samples in the grayed area. *Read it* , not
just pass over as "a method implementation error".


Constantly referencing your own work to support your argument is
pointless. If you have something new to present, let's see it - or
point out exactly why you think I'm in error.

Your statement at that link is:

"Each array has length property indicating the total amount of
elements (registered "data holders") currently containing in
the array."

Which is just one of many similar statements in the page that reiterates
your view. Constant repetition is not logical argument (that sounds so
Python-esque :-o ).
An important property not mentioned by your page is that any element
with an index not less than the length will be deleted, so if you have
an array with length 10 and you set it to 1, any element with index of
1 or greater is deleted.


Yes, as well is if you assign arrayObject = [] then all elements will
be removed. I did not want to mention in a public reading that the
Array.length can be used as a brute force ReDim (alloc) method. What


Above you showed concern for memory management, but now it doesn't matter?
you don't know will not hurt you :-)
Ignorance is bliss?
Array has enough methods to
accomplish it more gracefully and reliably.


But you didn't mention any of them (broken 'array methods' link noted).
Are you suggesting that changing the length of an array is an
unreliable way of removing elements?

That notion may have come from the blending of JavaScript arrays with
DOM concepts/methods. The two are not clearly separated in your
article, I think they should be.

Your page is quite good, most of what it says is useful and at a level
most newcomers will understand. But readers should not be taught things
that are inconsistent with fundamental principles.

--
Rob
Jul 28 '05 #16
"VK" <sc**********@yahoo.com> writes:
$listeners[$listeners.length] = $obj;


This is actually where I stoke because this code should not work at
all. Unless somewhere below you do $listeners.length++ and *then* it's
an abuse. Otherwise $listeners.length is always 0.


No. The length property of an Array is always larger than the largest
used array index, so when you assign to index 0, the length becomes
1, etc.

/L
--
Lasse Reichstein Nielsen - lr*@hotpop.com
DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
'Faith without judgement merely degrades the spirit divine.'
Jul 29 '05 #17
Richard Cornford wrote:
The - delete - operator does not have any impact on the length property
of an Array, so even deleting the last 'array index' property in an
array will not decrement the length. It is a good thing that javascript
arrays are sparse as this strategy would otherwise involve an ever
expanding memory use.
I was counting on the fact that they are sparse arrays - it takes the
element out of the for ( in ) loop, which is why it is so convenient (it
doesn't take it out of for(;;) loops though obviously).

To avoid incrementing your own counter? It seems over the top to take on
the baggage of an array just for that feature.
This makes sense. I always try to write easy to maintain (and read)
code, and still have efficiency and performance (I'm still learning,
though, so I don't always succeed). Since what you've said makes more
sense from a design view, and should have better performance, I'll take
your advise :-)

Incidentally, the dollar symbol is specifically mentioned in ECMA 262
(3rd edition, section 7.6) as being intended for use only in machine
generated code, so it should probably be avoided in javascript (that is
not machine generated). And because prefixing identifiers with dollar
symbols has special meaning in some other languages their use in
javascript (where they have no special meaning beyond signifying machine
generated Identifiers) is likely to be misleading.


Hmmm... I actually only use that because I intend to compress this code
for distribution using Dean Edwards' packer script:

http://dean.edwards.name/packer/

I've also noticed that some of the older browsers (3.0 era) don't like
that character in the identifiers, so I may just take them out, or
replace them with "_" it's easier that way anyway, because I don't have
to remember the check if any other identifier starts with the same first
letter (ex: Dean's tool replaces $variable with v).

I use them in php all the time as well, so it is quite natural to put
them there :-)

Thanks for the great info!

Kevin N.
Jul 29 '05 #18
VK

RobG wrote:
If you are discussing your stubbornness, then yes, it is demonstrated.
Oh yeh! But not from my part. This why I called it once "a discussion
about who's God is better". :-)

You may read an interesting discussion with Mr. Nielsen about the
previous variant of the article:
<http://groups-beta.google.com/group/comp.lang.javascript/browse_frm/thread/c12423afa53a28f8/bcf7ad952e27c998#bcf7ad952e27c998>
Subsequent readings have not changed the text or my understanding of it.
I see... So I guess you went through the example with the slice()
method and it did not change your clear understanding that this method
(as nearly all others) is simply broken...
It gives a good credit to your believe. My good luck to you to use
arrays in the matrix analysis. It's going to be as difficult as
navigate across the globe while thinking that the Earth is flat and
stays on three elephants.

The ECMA specification does not say...


ECMA doesn't need to say anything particular about array, as well as
define what "object", "algorithm", "program" and so is. These entities
appeared long before ECMA. So if you need to know what array is, ECMA
is not an authority of any kind. Their humble task was just include
properly and in proper relations with other sections, something that
was invented and described long before anyone of them got her/his first
payroll check. In this concern IBM repository is much more reliable
source of information:
<http://publib.boulder.ibm.com>
P.S. And yes, sorry for the broken link on array method. I had to drop
to take an urgent order. So far I just removed it.

Jul 29 '05 #19
VK wrote:
RobG wrote:
If you are discussing your stubbornness, then yes, it is demonstrated.

Oh yeh! But not from my part. This why I called it once "a discussion
about who's God is better". :-)

You may read an interesting discussion with Mr. Nielsen about the
previous variant of the article:
<http://groups-beta.google.com/group/comp.lang.javascript/browse_frm/thread/c12423afa53a28f8/bcf7ad952e27c998#bcf7ad952e27c998>
Subsequent readings have not changed the text or my understanding of it.

I see... So I guess you went through the example with the slice()
method and it did not change your clear understanding that this method
(as nearly all others) is simply broken...


Yes I did - I clearly understand what it does.

I can accept you expressing your opinion within this forum, but if you
are going to try to teach people about JavaScript arrays you need to
clearly separate fact from opinion.

Using your example and with a copy of the ECMAScript Language
Specification 3rd Edition December 1999 handy:

var arrayOne = new Array();
arrayOne[0] = "foo"
arrayOne[100] = "bar"
var arrayTwo = arrayOne.slice(0,50);
// arrayTwo.length == 50
arrayTwo will consist of the elements 0 up to but not including 50 of
arrayOne and therefore have a length of 50 (as per section 15.4.4.10).
arrayTwo[0] will be "foo"; all the other elements are undefined.

arrayTwo may actually have one defined element and 49 undefined ones,
or just one defined element and a length of 50 - however it is
actually implemented is irrelevant 99.99% of the time.

// But:
var arrayTwo = arrayOne.slice(99,200);
// arrayTwo.length == 2
// Only "in-within array" elements are counted
Which is exactly as per the specification - if the 'end' (in this case
200) is beyond arrayOne's length, then only the elements up to the end
of arrayOne are included. The second slice operation is the same as:

arrayTwo = arrayOne.slice( 99, arrayOne.length );

or

arrayTwo = [ arrayOne[99], arrayOne[100] ];

or

arrayTwo[1] = arrayOne[100];

in all cases, arrayTwo[0] will be undefined and arrayTwo.length = 2.

You then go on to assert:

As you can see, despite that mechanically (on the memory level) we
have only two elements in the entire arrayOne (arrayOne[0] and
arrayOne[100]), programmatically we have one continuos array of 101
element in total:
"foo", undefined, undefined, ... , undefined, "bar"
Which is your interpretation of things. Rather than use the
specification to state exactly what has occurred, you have chosen to
introduce your own jargon and leave readers confused.

You need to decide if you are teaching ECMAScript Language or VK's
opinion on life, the universe and everything.
It gives a good credit to your believe. My good luck to you to use
arrays in the matrix analysis. It's going to be as difficult as
navigate across the globe while thinking that the Earth is flat and
stays on three elephants.
Is it reasonable to make inferences about my system of beliefs based
on usage of a particular programming language? ;-p

And if my success so far is any measure, I'd have found your challenge
a doddle - pity the darn thing is an ovate spheroid (or so some believe).
The ECMA specification does not say...

ECMA doesn't need to say anything particular about array, as well as
define what "object", "algorithm", "program" and so is. These entities
appeared long before ECMA. So if you need to know what array is, ECMA
is not an authority of any kind. Their humble task was just include
properly and in proper relations with other sections, something that
was invented and described long before anyone of them got her/his first
payroll check. In this concern IBM repository is much more reliable
source of information:
<http://publib.boulder.ibm.com>


And that's the central issue - clearly pointing out on the one hand
what the spec says and on the other how arrays or other objects are
used in general in other contexts.

The ECMAScript Language specification is not an authority on arrays in
general, but it does prescribe the basic properties of JavaScript
arrays and therefore must be used as the primary reference when
describing their properties or behaviour.

[...]

--
Rob
Jul 30 '05 #20
RobG <rg***@iinet.net.auau> writes:

I agree with everything else you write, so I'll insist on nitpicking
this one thing:
The second slice operation is the same as:

arrayTwo = arrayOne.slice( 99, arrayOne.length );

or

arrayTwo = [ arrayOne[99], arrayOne[100] ];
These two are not completely equivalent, as the latter satisfies "0 in
arrayTwo" (or "arrayTwo.hasOwnProperty(0)"), whereas the first does
not. The equivalent would be:

arrayTwo = [,arrayOne[100]];

Ahem. Anyway ...
The ECMAScript Language specification is not an authority on arrays in
general, but it does prescribe the basic properties of JavaScript
arrays and therefore must be used as the primary reference when
describing their properties or behaviour.


I do believe VK has a point in describing Arrays at two levels: the
implementation and the abstract concept, only he doesn't make the
point very clearly.

The specification only states the implementation, and leaves the
abstraction up to the user. Unlike other languages, ECMAScript doesn't
hide its implementation, which allows us to use it in other ways than
how the abstract concept looks at it - breaking the abstraction.
In as "hacky"" a language as Javascript, I wouldn't put it past its
inventors to consider that a good thing :)

/L
--
Lasse Reichstein Nielsen - lr*@hotpop.com
DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
'Faith without judgement merely degrades the spirit divine.'
Jul 30 '05 #21
VK

RobG wrote:
Using your example and with a copy of the ECMAScript Language
Specification 3rd Edition December 1999 handy:

> var arrayOne = new Array();
arrayOne[0] = "foo"
arrayOne[100] = "bar"
var arrayTwo = arrayOne.slice(0,50);
// arrayTwo.length == 50

arrayTwo will consist of the elements 0 up to but not including 50 of
arrayOne and therefore have a length of 50 (as per section 15.4.4.10).
arrayTwo[0] will be "foo"; all the other elements are undefined.

arrayTwo may actually have one defined element and 49 undefined ones,
or just one defined element and a length of 50 - however it is
actually implemented is irrelevant 99.99% of the time.

> // But:
var arrayTwo = arrayOne.slice(99,200);
// arrayTwo.length == 2
// Only "in-within array" elements are counted

Which is exactly as per the specification - if the 'end' (in this case
200) is beyond arrayOne's length, then only the elements up to the end
of arrayOne are included.
You then go on to assert:

> As you can see, despite that mechanically (on the memory level) we
have only two elements in the entire arrayOne (arrayOne[0] and
arrayOne[100]), programmatically we have one continuos array of 101
element in total:
"foo", undefined, undefined, ... , undefined, "bar"

Which is your interpretation of things.


Sorry, and what is *your* interpretation of things? You just stated
(you were just forced to): "elements from ... to...". Because it's
right: array consists of the number of elements length-1 *when we are
using array as array*.
In the particular for array methods where are always 0...length-1
elements in array. If you have another interpretation of "things" then
state it.

So far your interpretation as I get it could be summarized this way:
"Array consists of length-1 elements which we can see clearly by
applying array methods. Array consists of only defined elements and it
has numeric property 'length'."

With all my respect, it's not an interpretation, but a loosely made
aporia.

Jul 30 '05 #22
VK wrote:
RobG wrote:
[...]
Which is your interpretation of things.

Sorry, and what is *your* interpretation of things?


I think of an array of having as many elements as its length, with
only those that have been defined as taking up any space. But that is
just for convenience - if an array should behave in some way different
to my concept of it but in accordance with its definition, then I will
accept that as a failure of my concept, not of the array.

If ultimately I am unable to reconcile my concepts with the reality of
the platform, I'll use something else.

You just stated
(you were just forced to): "elements from ... to...". Because it's
right: array consists of the number of elements length-1 *when we are
using array as array*.
In the particular for array methods where are always 0...length-1
elements in array. If you have another interpretation of "things" then
state it.
I guess this is where it gets difficult. I don't consider the
undefined elements to actually exist, they are kind of like credit
that I can use if I wish and only exist if I do use them. And I can
use them up to my limit unless I extend my credit.

Gosh, that's a pretty horrid metaphor but there you go.

So far your interpretation as I get it could be summarized this way:
"Array consists of length-1 elements which we can see clearly by
applying array methods. Array consists of only defined elements and it
has numeric property 'length'."
Yes, near enough.
With all my respect, it's not an interpretation, but a loosely made
aporia.


You like your philosophy I see! I had to look 'aporia' up:

“a logical contradiction beyond rational resolution”.

<URL:http://www.litencyc.com/php/stopics.php?rec=true&UID=1578>

You are free to hold that opinion - it's rational to me though maybe a
bit of a spin-out for some! :-)

--
Rob
Jul 30 '05 #23
VK wrote:
RobG wrote: <snip>
>> As you can see, despite that mechanically (on the memory level)
we have only two elements in the entire arrayOne (arrayOne[0]
and arrayOne[100]), programmatically we have one continuos array
of 101 element in total:
"foo", undefined, undefined, ... , undefined, "bar"

Which is your interpretation of things.


Sorry, and what is *your* interpretation of things?
You just stated (you were just forced to): "elements from
... to...". Because it's right: array consists of the number
of elements length-1 *when we are using array as array*.
In the particular for array methods where are always
0...length-1 elements in array. If you have another
interpretation of "things" then state it.


The Array methods; slice, reverse, concat, shift and unshift have (ECMA
262) specified behaviour that masks the nature of their Array object.
They each generate a sequence of numeric values limited by the Array's
length property and then use those numeric values, converted into
strings, with the Array's [[Get]] method to acquire a value and then use
the Array's [[Put]] method to assign that value to a property of an
Array.

Because the [[Get]] method of ECMAScritp objects (and so Arrays) returns
Undefined when the object does not have a property with the
corresponding name, but the [[Put]] method creates a property with the
corresponding name when there is no pre-existing property, the
application of an array method may produce a result that is
significantly different from the original Array.

A good example is the - reverse - method (as it acts upon the array
itself instead of producing an array result).

Using an ECMA 262 conforming browser such as Mozilla:-

var a = [];
a[0] = 'foo';
a[99] = 'bar'

- creates and array with a length property of 100, and counting its
defined elements with:-

var count = 0;
for(var prop in a){
++count;
}
alert(count);

- produces a count of 2. But then applying:-

a.reverse();

- and repeating:-

var count = 0;
for(var prop in a){
++count;
}
alert(count);

- produces a count of 100. The act of calling [[Get]] with each number
in the range 0 to (array.length-1) and then calling [[Put]] has created
all of those properties, regardless of whether they existed before the
call to reverse.

Thus, if the Array methods make the array look as if it is a continuous
sequence of properties instead of an object with possibly fewer existing
'array index' properties than 0 to (array.length-1) would accommodate,
that may be because the specified action of the methods is to create an
object that does actually have all of those properties. The results of
those method calls imply nothing about the objects on which they are
called.

In ECMAScript we can create, and work with, an object such as:-

var a = [];
a[4294967294] = 'foo';

- without flooding the entire OS memory map, precisely because the
underlying object does not have 4294967295 existing properties. And we
can enumerate the properties of that object with a for/in loop and
expect to see the result in our lifetime. We can also be sure that
calling the - reverse - method of that object in an ECMA 262 conforming
environment would be a somewhat foolish thing to do.

There is a general concept of what an 'array' is, stressing an ordered
arrangement, and a concept more specific to computing in general that
places more stress on the subscript/index. ECMAScript demonstrates that
the concept can be satisfied by many structures. For practical purposes
it is only necessary that the 'length' of an array (or combination of
its upper and lower bounds, where they may both be variable) expresses
the limits of its contents, and that accessing items within those limits
always has a consistent outcome.

Because the ECMAScript Array's special [[Put]] method may interact with
its - length - property upon assignment operations, and the native
ECMAScript object's [[Get]] method always returns a value (which may be
the Undefined value, if that is the value of the property and whenever
the property does not exist) we have an object that may be treated as a
continuous sequence of ordered storage locations limited by the arrays
length without any need for it to actually possess such a sequence of
storage locations. The general concept is satisfied and can be used in
designing code to be implemented in ECMAScript.

However, while the general concept of an array can be employed in script
authoring it can only benefit the author of such scripts to understand
the nature of the object that they are using. Take Kevin Newman's code
as an example. If the ECMAScript Array implementation really was a
continuos sequence of indexed storage locations then his implementation
would be objectively bad (as it must get slower the more it operated,
and it must consume progressively more memory as the Array got longer).
As it is his implementation is fine from a practical point of view. The
worst that can be said of it is that it doesn't 'feel' right to be using
an Array just for its self-incrementing - length - property (very much a
matter of opinion).

It is not in satisfying the general concept of 'array' that the
ECMAScript author needs to understand the object being used, it is when
they go outside of that concept. There is the use of an Array as an
'associative array' and the oft repeated question as to why the
assignment of a non-'array index' property does not affect the Array's
length. There is the employment of an array as a repository for
name/value pairs that can also be looped over, where the named
properties store integer values that refer to the real vales stored
under 'array index' property names. And host of other applications of
Arrays that can only be properly explained by an appreciation of what an
ECMAScript Array really is.
So far your interpretation as I get it could be summarized
this way: "Array consists of length-1 elements which we can
see clearly by applying array methods. Array consists of only
defined elements and it has numeric property 'length'."

With all my respect, it's not an interpretation, but a loosely
made aporia.


Your unfounded opinion that the Array methods might demonstrate a
non-sparseness in ECMAScript arrays is at the root of your perception of
a contradiction. The object that is an ECMAScript array is quite capable
of being used as if it was a continuos sequence of indexed storage
locations without actually being a continuos sequence of storage
locations. ECMA 262 explains both how and why Arrays behave in the way
they do, both in satisfying the general concept of an 'array' and in
providing behaviour that is well outside of that concept.

Richard.
Jul 30 '05 #24
On 28/07/2005 23:55, Kevin Newman wrote:
Michael Winter wrote:


[snip]
I would (and in fact, do) use a list for similar code.


Do you have an example of what you mean by a list?


Using recursion:

var listeners = null;

function Node(d) {
var n = null;

this.notify = function(v) {
d.unFocusHistoryUpdate(v);
if(n) {n.notify(v);}
};
this.add = function(o) {
if(d == o) {return;}
if(n) {n.add(o);}
else {n = new Node(o);}
};
this.remove = function(o) {
if(d == o) {return n;}
if(n) {n = n.remove(o);}
return this;
};
}

function _NotifyListeners(v) {
if(listeners) {listeners.notify(v);}
}
this.AddListener = function(o) {
/* ... */
if(listeners) {listeners.add(o);}
else {listeners = new Node(o);}
/* ... */
}
this.RemoveListener = function(o) {
if(listeners) {listeners = listeners.remove(o);}
};
Using iteration:

var listeners = null;

function _NotifyListeners(v) {
var n = listeners;

while(n) {
n.data.unFocusHistoryUpdate(v);
n = n.next;
}
}
this.AddListener = function(o) {
var n = listeners,
p;
/* ... */
if(n) {
do {
if(n.data == o) {return;}
p = n;
} while((n = n.next));
p.next = {data : o};
} else {
listeners = {data : o};
}
/* ... */
};
this.RemoveListener = function(o) {
var n = listeners.next,
p = listeners;

if(p.data == o) {listeners = n;}
else if(n) {
do {
if(n.data == o) {
p.next = n.next;
return;
}
p = n;
} while((n = n.next));
}
};

[snip]

Mike

--
Michael Winter
Prefix subject with [News] before replying by e-mail.
Jul 30 '05 #25
This entire post has been very instructive. Thank you for that!

btw, I'm using an object now, and incrementing my own variable - you
have convinced me :-)

Kevin N.
Jul 30 '05 #26
> This entire post has been very instructive. Thank you for that!

btw, I'm using an object now, and incrementing my own variable - you
have convinced me :-)


You may have drawn the wrong conclusion, perhaps as a consequence of
the large amount of misinformation spewed under this topic. Even the
title of this topic (Array and Hash (Associative array) in JavaScript
v.3.0) contains errors. A better title would have been "Array and
Object in ECMAScript Version 3".

The simple rule is this: If all of your indexes are non-negative
integers, use an array []. Otherwise, use an object {}.

http://www.crockford.com/javascript/survey.html
Jul 30 '05 #27
"Richard Cornford" <Ri*****@litotes.demon.co.uk> writes:
Using an ECMA 262 conforming browser such as Mozilla:-

var a = [];
a[0] = 'foo';
a[99] = 'bar' .... a.reverse();

- and repeating:-

var count = 0;
for(var prop in a){
++count;
}
alert(count);

- produces a count of 100.
Then Mozilla isn't ECMA 262 conforming, because ECMA262 v3 section
15.4.4.8 specifies the behavior of Array.prototype.reverse such that
the result should still be 2. Both Opera and IE gives 2.

Mozilla (in my case Firefox v1.04) have other array-related bugs,
e.g.,

var a = [0,,,,,,,,,,,,,,,,,,,19];

also gives a count of 20 elements in Firefox, but 2 in IE, Opera and
the ECMA 262 standard. Also, sort() has the same problem as reverse,
introducing elements that wasn't there in the original (Opera has
a bug there too).
The act of calling [[Get]] with each number
in the range 0 to (array.length-1) and then calling [[Put]] has created
all of those properties, regardless of whether they existed before the
call to reverse.


And the definition of reverse in ECMA 262 does two [[Get]]'s, and
then, depending on whether the object has properties of those names,
do either two [[Put]]'s, one [[Put]] and one [[Delete]], or two
[[Delete]]'s (rather superflous, when it just checked that neither
property existed).
/L
--
Lasse Reichstein Nielsen - lr*@hotpop.com
DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
'Faith without judgement merely degrades the spirit divine.'
Jul 30 '05 #28
Lasse Reichstein Nielsen wrote:
Richard Cornford writes:
Using an ECMA 262 conforming browser such as Mozilla:-

var a = [];
a[0] = 'foo';
a[99] = 'bar'

...
a.reverse();

- and repeating:-

var count = 0;
for(var prop in a){
++count;
}
alert(count);

- produces a count of 100.


Then Mozilla isn't ECMA 262 conforming, because ECMA262 v3
section 15.4.4.8 specifies the behavior of
Array.prototype.reverse such that the result should still
be 2. Both Opera and IE gives 2.

<snip>

You are right. And Mozilla is wrong in not having the result of its
Array methods being as sparse and the original object. Though that makes
it less reasonable of VK to assert that the array methods imply that
that arrays are continuous sequences of storage locations.

It also means that Mozilla browsers are open to 'malicious' actions such
as:-

var a = [];
a[4294967294] = 'x';
a.reverse();

- being harmless to IE while having Mozilla grind to a halt, and
eventually cripple the entire OS.

Richard.
Jul 31 '05 #29
Michael Winter wrote:
On 28/07/2005 23:55, Kevin Newman wrote:
Michael Winter wrote:

[snip]
I would (and in fact, do) use a list for similar code.

Do you have an example of what you mean by a list?

Using recursion:

var listeners = null;

function Node(d) {
var n = null;

this.notify = function(v) {
d.unFocusHistoryUpdate(v);
if(n) {n.notify(v);}
};
this.add = function(o) {
if(d == o) {return;}
if(n) {n.add(o);}
else {n = new Node(o);}
};
this.remove = function(o) {
if(d == o) {return n;}
if(n) {n = n.remove(o);}
return this;
};
}

function _NotifyListeners(v) {
if(listeners) {listeners.notify(v);}
}
this.AddListener = function(o) {
/* ... */
if(listeners) {listeners.add(o);}
else {listeners = new Node(o);}
/* ... */
}
this.RemoveListener = function(o) {
if(listeners) {listeners = listeners.remove(o);}
};
Using iteration:

var listeners = null;

function _NotifyListeners(v) {
var n = listeners;

while(n) {
n.data.unFocusHistoryUpdate(v);
n = n.next;
}
}
this.AddListener = function(o) {
var n = listeners,
p;
/* ... */
if(n) {
do {
if(n.data == o) {return;}
p = n;
} while((n = n.next));
p.next = {data : o};
} else {
listeners = {data : o};
}
/* ... */
};
this.RemoveListener = function(o) {
var n = listeners.next,
p = listeners;

if(p.data == o) {listeners = n;}
else if(n) {
do {
if(n.data == o) {
p.next = n.next;
return;
}
p = n;
} while((n = n.next));
}
};

[snip]

Mike


This is pretty spiffy! Thanks :-)

Kevin N.
Aug 1 '05 #30
I'm so confused :-)

Douglas Crockford wrote:
The simple rule is this: If all of your indexes are non-negative
integers, use an array []. Otherwise, use an object {}.


This is what I originally thought, which is why I used an array. But I'm
using for...in to iterate my array.

Having thought about this, I think it might be best to use a standard
for loop since that will be more consistent with an array, and it would
allow me to only iterate integer indexes, so that if someone messes with
Array.prototype to add Array.push or something similar, it will not get
iterated like it would with for...in.

I'll just have to figure out how to keep the indexes contiguous when I
remove an element (I'm guessing there is a way to do that using
Array.slice, instead of delete - I'll have to experiment).

Thanks for all the info, it's been fun :-)

Kevin N.
Aug 1 '05 #31
On 01/08/2005 17:31, Kevin Newman wrote:

[snip]
I'll just have to figure out how to keep the indexes contiguous when I
remove an element (I'm guessing there is a way to do that using
Array.slice, instead of delete - I'll have to experiment).


The Array.prototype.splice method[1] can be used to delete (and insert)
elements at arbitrary locations within an array. Essentially, it just
copies values about. However, this is a problem that I alluded to when I
mentioned the differences between sequential and linked data structures.
With the former, insertions and deletions at any location except the end
require all elements after the point of change to be shifted which, in a
large structure, can take a long time. With linked lists, it's simply a
matter of changing the links as the new element can be added anywhere in
memory (for insertion) or just forgotten about (for deletion).

Sequential structures offer fast, random look ups, but as yours will
always be complete iteration through the collection, this is only an
advantage when inserting or deletion at specific locations. Even then,
insertion for you will always be at the end once you've checked that the
new element is not a duplicate (more complete iteration). That just
leaves deletion, which should be rare anyway.

Despite how it may seem, I'm not necessarily pushing for you to use a
list. I do, but it's up to you to decide for yourself. Theoretical
reasons don't always in scripting, particularly as ECMAScript Arrays
don't have the same drawbacks that 'real' arrays do (including
reallocation during insertion).

Mike
[1] Not available in JScript 5 (usually IE5.0) and earlier.

--
Michael Winter
Prefix subject with [News] before replying by e-mail.
Aug 2 '05 #32
"Richard Cornford" <Ri*****@litotes.demon.co.uk> wrote in message
news:dc*******************@news.demon.co.uk...

You are right. And Mozilla is wrong in not having the result of its
Array methods being as sparse and the original object. Though that
makes
it less reasonable of VK to assert that the array methods imply that
that arrays are continuous sequences of storage locations.

It also means that Mozilla browsers are open to 'malicious' actions
such
as:-

var a = [];
a[4294967294] = 'x';
a.reverse();

- being harmless to IE while having Mozilla grind to a halt, and
eventually cripple the entire OS.

Richard.


Not harmless in Internet Explorer 6.0.2900 here. CPU usage climbed to
90+% and stayed there for several minutes. jscript.dll version
5.6.0.8825

In Firefox 1.0.6, CPU rises to 90+% and stays there, eventually the
application generates an error and

Opera 8.02 returns almost immediately from a.reverse(), but attempting
to do -document.write(a);- results in a hung application.

--
Grant Wagner <gw*****@agricoreunited.com>
comp.lang.javascript FAQ - http://jibbering.com/faq
Aug 2 '05 #33
"Grant Wagner" <gw*****@agricoreunited.com> writes:
"Richard Cornford" <Ri*****@litotes.demon.co.uk> wrote in message
news:dc*******************@news.demon.co.uk...
var a = [];
a[4294967294] = 'x';
a.reverse();

Opera 8.02 returns almost immediately from a.reverse(), but attempting
to do -document.write(a);- results in a hung application.


That's because the default string representation of that array would
be an "x" followed by 4294967294 commas. You asked for it, prepare to
wait :)

/L
--
Lasse Reichstein Nielsen - lr*@hotpop.com
DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
'Faith without judgement merely degrades the spirit divine.'
Aug 2 '05 #34


Lasse Reichstein Nielsen wrote:
Then Mozilla isn't ECMA 262 conforming, because ECMA262 v3 section
15.4.4.8 specifies the behavior of Array.prototype.reverse such that
the result should still be 2. Both Opera and IE gives 2.


The bug with reverse has been fixed recently in Mozilla so in a Mozilla
1.8 nightly or Deer Park nightly the result should be 2 too.
Here is the bug:
<https://bugzilla.mozilla.org/show_bug.cgi?id=299738>

--

Martin Honnen
http://JavaScript.FAQTs.com/
Aug 3 '05 #35


Lasse Reichstein Nielsen wrote:

Mozilla (in my case Firefox v1.04) have other array-related bugs,
e.g.,

var a = [0,,,,,,,,,,,,,,,,,,,19];

also gives a count of 20 elements in Firefox, but 2 in IE, Opera and
the ECMA 262 standard.


This is filed as a bug but not fixed yet:
<https://bugzilla.mozilla.org/show_bug.cgi?id=260106>

--

Martin Honnen
http://JavaScript.FAQTs.com/
Aug 3 '05 #36

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

4 posts views Thread by Robert | last post: by
5 posts views Thread by Denis Perelyubskiy | last post: by
14 posts views Thread by Yereth Jansen | last post: by
7 posts views Thread by Robert Mark Bram | last post: by
104 posts views Thread by Leszek | last post: by
30 posts views Thread by josh | last post: by
5 posts views Thread by M. Fisher | last post: by
reply views Thread by suresh191 | last post: by
4 posts views Thread by guiromero | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.