In general, when looping through an array, you want to use its length
property as the book's solution did. Your solution should be just fine in this particular situation as well, but it has a weakness: It's perfectly valid for an entry in an array to be 0
, null
, undefined
, or false
, all of which are "falsey" values and so document.links[i]
could be false even though you weren't at the end of the array.
Example:
var index, a;
a = [3, 2, 1, 0, -1, -2];
for (index = 0; a[index]; ++index) {
alert(a[index]);
}
That will alert 3
, 2
, and 1
, but then stop. Compare to:
var index, a;
a = [3, 2, 1, 0, -1, -2];
for (index = 0; index < a.length; ++index) {
alert(a[index]);
}
...which will alert 3
, 2
, 1
, 0
, -1
, and -2
.
You might see code that looks like this: for (index in a)
. In general don't use that to loop through array indexes, it's based on a misconception of what for..in
does. (More on that below.)
(There is another, new way of looping through array entries has been added as of the new 5th edition specification: The forEach
function. You give it a function, and it calls it for each element in the array. Details in this other answer.. Sadly, IE8 doesn't support it, but it's one of the things that can be "shimmed" — search for "es5 shim" for multiple options.)
When learning about arrays, it's important to know that Javascript arrays are very different from arrays in most other languages. For one thing, they're not (necessarily) arrays at all; in fact, they're just normal Javascript objects with a couple of special features added on. Javascript objects are property maps, they map keys to values. For instance:
var obj = {foo: 1};
That obj
object maps the key "foo"
(a string) to the value 1
. You can access that property either by using a literal name in your code, or by using []
and a string. And of course, if you're doing the latter, you can use any string (literal or from a variable or from an expression, etc.). So all of these have the same result:
x = obj.foo;
x = obj["foo"];
name = "foo";
x = obj[name];
name = "o";
x = obj["f" + name + name];
...you get the idea; as long as what you use within the []
evaluates to a string, you can look up the value using that key. But Javascript also does implicit coercion, so this works:
var obj = {"1": "one"};
alert(obj[1]); // alerts "one"
There I've mapped a property named "1"
to the value "one"
. But then I look it up with obj[1]
, using a number rather than a string. That's okay, the interpreter will turn it into a string for me and then do the key lookup.
What does all of this have to do with arrays? This: Array indexes are just property names. A Javascript array is a normal object that maps keys to values, with these special features:
Whenever you set a property whose name can be interpreted as a number, if that number is greater than the current maximum index present in the array, the length
property is changed. So:
var a = ["zero"];
alert(a.length); // alerts 1
a[3] = "three";
alert(a.length); // alerts 4, because the max index is now 3
Whenever you set length
, if there are properties with numeric names that have a value greater than or equal to the new length, those properties are deleted from the object.
var a = ["zero", "one", "two", "three"];
alert(a[3]); // alerts "three"
a.length = 3;
alert(a[3]); // alerts "undefined", the "3" property has been deleted
// only the "0", "1", and "2" properties remain
They have various properties for functions they inherit from the Array.prototype, like join
or splice
.
That's it. Nothing at all like arrays in C, C++, Java, or most other languages.
Since arrays are just objects with a couple of extra features, you can put other, non-numeric properties on arrays if you want to:
var a = ["zero", "one", "two"];
a.foo = "bar";
alert(a[1]); // alerts "one", 1 is implicitly coerced to "1"
alert(a["1"]); // alerts "one"
alert(a.foo); // alerts "bar"
alert(a["foo"]); // alerts "bar"
And this is where the for..in
thing breaks down: Because for..in
does not loop through array indexes, it loops through property names:
var a, name;
a = [1, 2, 3];
a.foo = "bar";
for (name in a) {
alert(name);
}
This alerts "1"
, "2"
, "3"
, and "foo"
(in no particular order). You can see how if you'd assumed that it did just array indexes, you'd be in trouble! You can use it to loop array indexes, but it's more complicated than it's worth:
for (name in a) {
if (String(Number(name)) === name && a.hasOwnProperty(name)) {
alert(name);
}
}
That first checks to see if the property name is a number, and then checks to see that the property is defined on a
itself, not the Array.prototype (remember that arrays inherit properties from the Array prototype). (To be fair, this latter check is probably not all that important; if someone is adding numerically-named properties to the Array prototype, they're doing a very Bad Thing(tm).)