Understanding Arrays within Arrays

M

MG

I am learning javascript from a book.

The example below is aimed at demonstrating drop down select menus. The
alerts (commented out) were added by me.

The example uses arrays within arrays, but doesn't explain them at all well.
So I have some questions:

What syntax would return Australia, France, Japan, New Zealand ?

Why does cities[1][1] not work, but cities['France'][1] does?

Any other useful help with arrays within arrays would be appreciated.

Thanks
MG



=====================

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Related Select Test</title>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
<script type="text/javascript">
<!--
// Create an array to hold the cities for each country
var cities = new Array(4);
cities["Australia"] =
["Sydney", "Melbourne", "Canberra", "Perth", "Brisbane"];
cities["France"] =
["Paris", "Lyons", "Nice", "Dijon"];
cities["Japan"] = ["Tokyo", "Kyoto", "Osaka", "Nara"];
cities["New Zealand"] =
["Auckland", "Wellington", "Christchurch", "Dunedin", "Queenstown"];

//alert(cities); does not work
//alert(cities[1]); undefined
//alert(cities[1][1]); does not work
//alert(cities['France']); works
//alert(cities['France'][1]); works


function removeOptions(optionMenu)
{
for (var i=0; i < optionMenu.options.length; i++)
optionMenu.options = null;
}
function addOptions(optionList, optionMenu)
{
removeOptions(optionMenu); // clear out the options
for (var i=0; i < optionList.length; i++)
optionMenu = new Option(optionList, optionList);
}
//-->
</script>
</head>
<body>
<h2>Vacation Chooser</h2>
<form name="testform" id="testform" action="#" method="get">
Country:
<select name="country" id="country"
onchange="addOptions(cities[this.options[this.selectedIndex].text],document.testform.city);">
<option selected="selected">Australia</option>
<option>France</option>
<option>Japan</option>
<option>New Zealand</option>
</select>
City:
<select name="city" id="city">
<option>Sydney</option>
<option>Melbourne</option>
<option>Canberra</option>
<option>Perth</option>
<option>Brisbane</option>
</select>
</form>
</body>
</html>
 
J

Jeremy J Starcher

I am learning javascript from a book.

Good idea. Wish there any books that could be wholeheartedly recommended.
The example below is aimed at demonstrating drop down select menus. The
alerts (commented out) were added by me.

The example uses arrays within arrays, but doesn't explain them at all
well. So I have some questions:

Actually ... it doesn't.

This has been a reoccurping topic here on c.l.js I almost think we need
a new FAQ entry. I'll even provide the basis.

Javascript (or ECMAScript to be precise) has Objects. An object can hold
key/value pairs, like this:

var capitals = {
"France":"Paris",
"USA":"Washington DC."
};

alert(capitals.France); // Paris
alert(capitals['France']; // Paris

The doted notation has some limits on what key values may be used, the
bracketed method has more flexibility.

Arrays, on the other hand, use NUMERIC keys.

var christmasList = [
"My Front Teeth",
"Five calling birds"
];

alert(christmasList[1]);

The confusion comes from this ...

In Javascript arrays inherit from objects. EVERYTHING you can do with an
object you can do with an array. Arrays are objects. But -- when you
use a non-numeric key, you loose all of the array special features for
that element.

var a = ["Zero", "One", "Two"];
for (var i = 1; i < a.length; i++) {
alert(a);
}

a['hopeless'] = "You'll never see me in an array loop";

So the short of it is.. if you want numeric keys, use an array. If you
want string keys, use an object.

What syntax would return Australia, France, Japan, New Zealand ?

Why does cities[1][1] not work, but cities['France'][1] does?

Any other useful help with arrays within arrays would be appreciated.

Thanks
MG



=====================

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html
xmlns="http://www.w3.org/1999/xhtml"> <head>
<title>Related Select Test</title>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"
/> <script type="text/javascript">
<!--
// Create an array to hold the cities for each country var cities = new
Array(4);
cities["Australia"] =
["Sydney", "Melbourne", "Canberra", "Perth", "Brisbane"];
cities["France"] =
["Paris", "Lyons", "Nice", "Dijon"];
cities["Japan"] = ["Tokyo", "Kyoto", "Osaka", "Nara"]; cities["New
Zealand"] =
["Auckland", "Wellington", "Christchurch", "Dunedin", "Queenstown"];

//alert(cities); does not work
//alert(cities[1]); undefined
//alert(cities[1][1]); does not work //alert(cities['France']); works
//alert(cities['France'][1]); works


function removeOptions(optionMenu)
{
for (var i=0; i < optionMenu.options.length; i++) optionMenu.options
= null;
}
function addOptions(optionList, optionMenu) {
removeOptions(optionMenu); // clear out the options for (var i=0; i <
optionList.length; i++) optionMenu = new Option(optionList,
optionList); }
//-->
</script>
</head>
<body>
<h2>Vacation Chooser</h2>
<form name="testform" id="testform" action="#" method="get"> Country:
<select name="country" id="country"
onchange="addOptions(cities[this.options [this.selectedIndex].text],document.testform.city);">
<option selected="selected">Australia</option> <option>France</option>
<option>Japan</option>
<option>New Zealand</option>
</select>
City:
<select name="city" id="city">
<option>Sydney</option>
<option>Melbourne</option>
<option>Canberra</option>
<option>Perth</option>
<option>Brisbane</option>
</select>
</form>
</body>
</html>
 
M

MG

Jeremy J Starcher said:
Good idea. Wish there any books that could be wholeheartedly recommended.


Actually ... it doesn't.

I understand what you mean. In the example, I replaced this line:
var cities = new Array(4);
with this one:
var cities = new Object();
Everything works just the same.

So the book is very misleading when it says "Create an array to hold the
cities for each country"



This has been a reoccurping topic here on c.l.js I almost think we need
a new FAQ entry. I'll even provide the basis.

Javascript (or ECMAScript to be precise) has Objects. An object can hold
key/value pairs, like this:

var capitals = {
"France":"Paris",
"USA":"Washington DC."
};

alert(capitals.France); // Paris
alert(capitals['France']; // Paris

The doted notation has some limits on what key values may be used, the
bracketed method has more flexibility.

Arrays, on the other hand, use NUMERIC keys.

var christmasList = [
"My Front Teeth",
"Five calling birds"
];

alert(christmasList[1]);

The confusion comes from this ...

In Javascript arrays inherit from objects. EVERYTHING you can do with an
object you can do with an array. Arrays are objects. But -- when you
use a non-numeric key, you loose all of the array special features for
that element.

var a = ["Zero", "One", "Two"];
for (var i = 1; i < a.length; i++) {
alert(a);
}

a['hopeless'] = "You'll never see me in an array loop";

So the short of it is.. if you want numeric keys, use an array. If you
want string keys, use an object.

What syntax would return Australia, France, Japan, New Zealand ?

Why does cities[1][1] not work, but cities['France'][1] does?

Any other useful help with arrays within arrays would be appreciated.

Thanks
MG



=====================

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html
xmlns="http://www.w3.org/1999/xhtml"> <head>
<title>Related Select Test</title>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"
/> <script type="text/javascript">
<!--
// Create an array to hold the cities for each country var cities = new
Array(4);
cities["Australia"] =
["Sydney", "Melbourne", "Canberra", "Perth", "Brisbane"];
cities["France"] =
["Paris", "Lyons", "Nice", "Dijon"];
cities["Japan"] = ["Tokyo", "Kyoto", "Osaka", "Nara"]; cities["New
Zealand"] =
["Auckland", "Wellington", "Christchurch", "Dunedin", "Queenstown"];

//alert(cities); does not work
//alert(cities[1]); undefined
//alert(cities[1][1]); does not work //alert(cities['France']); works
//alert(cities['France'][1]); works


function removeOptions(optionMenu)
{
for (var i=0; i < optionMenu.options.length; i++) optionMenu.options
= null;
}
function addOptions(optionList, optionMenu) {
removeOptions(optionMenu); // clear out the options for (var i=0; i <
optionList.length; i++) optionMenu = new Option(optionList,
optionList); }
//-->
</script>
</head>
<body>
<h2>Vacation Chooser</h2>
<form name="testform" id="testform" action="#" method="get"> Country:
<select name="country" id="country"
onchange="addOptions(cities[this.options [this.selectedIndex].text],document.testform.city);">
<option selected="selected">Australia</option> <option>France</option>
<option>Japan</option>
<option>New Zealand</option>
</select>
City:
<select name="city" id="city">
<option>Sydney</option>
<option>Melbourne</option>
<option>Canberra</option>
<option>Perth</option>
<option>Brisbane</option>
</select>
</form>
</body>
</html>

 
J

Jeremy J Starcher

I understand what you mean. In the example, I replaced this line: var
cities = new Array(4);
with this one:
var cities = new Object();

It is better style to write that as:
var cities = {};

In this case, it won't make any difference, but in this example:
var array1 = new Array(5);
var array2 = [5];

do two, quite different things.
array1.length === 5, with all elements being undefined.
array2.length === 1 && array[0] === 5

var array1 = new Array(5,6);
var array2 = [5,6];

do exactly the same thing. Avoid the confusion and use "[]" and "{}"
syntax.

Everything works just the same.
Exactly.
So the book is very misleading when it says "Create an array to hold the
cities for each country"

Most books are misleading. In Javascript, that tends to be even more
true than usual. Some authors know a language like PHP or PERL where
arrays can have both string and numeric keys. They try it and it seems
to work, so thats what they write.

((Sorry about not trimming my quote last time.))
 
T

Thomas 'PointedEars' Lahn

Jeremy said:
This has been a reoccurping topic here on c.l.js I almost think we need
a new FAQ entry. I'll even provide the basis.

It would be better if you wouldn't.
Javascript (or ECMAScript to be precise) has Objects. An object can hold
key/value pairs, like this:

An object holds (attributed) name-value pairs that are called "properties".

,-[ES5, 4.2 Language Overview (non-normative)]
|
| An ECMAScript object is a collection of properties each with zero or more
| attributes that determine how each property can be used [...].
| Properties are containers that hold other objects, primitive values, or
| functions.

,-[ES5, 4.3 Definitions (normative)]
|
| 4.3.26
| property
| association between a name and a value that is a part of an object.
|
| NOTE
| Depending upon the form of the property the value may be represented
| either directly as a data value (a primitive value, an object, or a
| function object) or indirectly by a pair of accessor functions.
var capitals = {
"France":"Paris",
"USA":"Washington DC."
};

alert(capitals.France); // Paris
alert(capitals['France']; // Paris

The doted notation has some limits on what key values may be used, the
bracketed method has more flexibility.

There are no keys, there are property names. Property names that are
identifiers can be used with the dot _notation_; other names require the
bracket notation.

,-[ES5, 11.2.1 Property Accessors]
|
| Properties are accessed by name, using either the dot notation:
|
| MemberExpression . IdentifierName
| CallExpression . IdentifierName
|
| or the bracket notation:
|
| MemberExpression [ Expression ]
| CallExpression [ Expression ]
|
| The dot notation is explained by the following syntactic conversion:
|
| MemberExpression . IdentifierName
|
| is identical in its behaviour to
|
| MemberExpression [ <identifier-name-string> ]
|
| and similarly
|
| CallExpression . IdentifierName
|
| is identical in its behaviour to
|
| CallExpression [ <identifier-name-string> ]
|
| where <identifier-name-string> is a string literal containing the same
| sequence of characters after processing of Unicode escape sequences as
| the IdentifierName.
Arrays, on the other hand, use NUMERIC keys.

All property names are string values. Some property names are special with
Arrays, though. (See below.)
var christmasList = [
"My Front Teeth",
"Five calling birds"
];

alert(christmasList[1]);

window.alert(christmasList["1"]);

is equivalent because property names are strings, and the bracket property
accessor converts its parameter to a primitive string value before property
access if necessary.
The confusion comes from this ...

That you don't really know what you are talking about?
In Javascript arrays inherit from objects.

There is no "Javascript":
<http://PointedEars.de/es-matrix> (updated yesterday)

In ECMAScript implementations like JavaScript or JScript, array
functionality is encapsulated by objects, Array instances.
EVERYTHING you can do with an object you can do with an array.

No. To begin with, there are some values that you cannot assign to the
`length' property of Array instances because it is special, where there is
no problem assigning them to the `length' property of Object instances.
Most notably, though, you cannot inherit from Array.prototype and keep the
behavior of Array instances.
Arrays are objects.

Somewhat correct.
But -- when you use a non-numeric key, you loose all of the array special
features for that element.

The proper spelling is _lose_, and that is only correct if you defined "non-
numeric key" as the opposite of what is specified as special for properties
of Array instances in the ECMAScript Language Specification (here quoted
from Edition 5):

| 15.4 Array Objects
|
| Array objects give special treatment to a certain class of property names.
| A property name P (in the form of a String value) is an array index if and
| only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal
| to 2^32−1. A property whose property name is an array index is also called
| an element. Every Array object has a length property whose value is always
| a nonnegative integer less than 2^32. The value of the length property is
| numerically greater than the name of every property whose name is an array
| index; whenever a property of an Array object is created or changed, other
| properties are adjusted as necessary to maintain this invariant.
| Specifically, whenever a property is added whose name is an array index,
| the length property is changed, if necessary, to be one more than the
| numeric value of that array index; and whenever the length property is
| changed, every property whose name is an array index whose value is not
| smaller than the new length is automatically deleted. This constraint
| applies only to own properties of an Array object and is unaffected by
| length or array index properties that may be inherited from its
| prototypes.

In short: "numeric keys" that are not representable as unsigned 32-bit
integer values less than 2 to the power of 32 do not access array elements
either.
var a = ["Zero", "One", "Two"];
for (var i = 1; i < a.length; i++) {
alert(a);
}


That is a misleading example. The `for' loop should start at 0.
a['hopeless'] = "You'll never see me in an array loop";

What is an "array loop"? Consider this:

for (var i in a)
{
window.alert(a);
}
So the short of it is.. if you want numeric keys, use an array. If you
want string keys, use an object.

Rubbish. Good advice is that one should use an Array instance only when
one needs the special properties and behavior of Array instances. That
includes, but is not limited to, use of the `length' property.

Please trim your quotes to the relevant minimum.


PointedEars
 
T

Thomas 'PointedEars' Lahn

Thomas said:
The proper spelling is _lose_, and that is only correct if you defined
"non- numeric key" as the opposite of what is specified as special for
properties of Array instances in the ECMAScript Language Specification
(here quoted from Edition 5):

| 15.4 Array Objects
|
| Array objects give special treatment to a certain class of property
| names. A property name P (in the form of a String value) is an array
| index if and only if ToString(ToUint32(P)) is equal to P and ToUint32(P)
| is not equal to 2^32−1. A property whose property name is an array index
| is also called an element. Every Array object has a length property
| whose value is always a nonnegative integer less than 2^32. The value of
| the length property is numerically greater than the name of every
| property whose name is an array index; whenever a property of an Array
| object is created or changed, other properties are adjusted as necessary
| to maintain this invariant. Specifically, whenever a property is added
| whose name is an array index, the length property is changed, if
| necessary, to be one more than the numeric value of that array index;
| and whenever the length property is changed, every property whose name
| is an array index whose value is not smaller than the new length is
| automatically deleted. This constraint applies only to own properties of
| an Array object and is unaffected by length or array index properties
| that may be inherited from its prototypes.

In short: "numeric keys" that are not representable as unsigned 32-bit
integer values less than 2 to the power of 32

.... minus 1 ...
do not access array elements either.

(That is necessary because the element at index 2^32-1 would set the
`length' property value to 2^32, which is forbidden.)


PointedEars
 

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,982
Messages
2,570,186
Members
46,739
Latest member
Clint8040

Latest Threads

Top