1

The question is this:

Create a page with a number of links. Then write code that fires on the window onload event, displaying the href of each of the links on the page.

And this is my solution

<html>
<body language="Javascript" onload="displayLink()">
<a href="http://www.google.com/">First link</a>
<a href="http://www.yahoo.com/">Second link</a>
<a href="http://www.msn.com/">Third link</a>

<script type="text/javascript" language="Javascript">
function displayLink()
{
 for(var i = 0;document.links[i];i++)
 {
 alert(document.links[i].href);
 }
}
</script>

</body>
</html>

This is the answer provided by the book

<html>
<head>
<script language=”JavaScript” type=”text/javascript”>
function displayLinks()
{
 var linksCounter;
 for (linksCounter = 0; linksCounter < document.links.length; linksCounter++)
 {
  alert(document.links[linksCounter].href);
 }
}
</script>
</head>
<body onload=”displayLinks()”>
<A href=”link0.htm” >Link 0</A>
<A href=”link1.htm”>Link 2</A>
<A href=”link2.htm”>Link 2</A>
</body>
</html>

Before I get into the javascript tutorial on how to check user browser version or model,I was using the same method as the example,by acessing the length property of the links array for the loop,but after I read through the tutorial,I find out that I can also use this alternative ways,by using the method that the test condition will evalute to true only if the document.links[i] return a valid value,so does my code is written using the valid method??If it's not,any comment regarding how to write a better code??Correct me if I'm wrong,I heard some of the people say "a good code is not evaluate solely on whether it works or not,but in terms of speed,the ability to comprehend the code,and could posssibly let others to understand the code easily".Is is true??

demongolem
  • 9,474
  • 36
  • 90
  • 105
caramel1995
  • 2,968
  • 10
  • 44
  • 57

2 Answers2

5

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

Community
  • 1
  • 1
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 1
    +1 I faved this question, but I'd rather like to fav this answer. It is one of the best explanations I've ever read (in over 15 years). – GitaarLAB Dec 10 '13 at 04:09
0

Yes, it's true that the code should not only work but also be easy to comprehend. It's called manageability, and is a very important aspect of writing good code.

Let's look at some differences and some problems in your code and the provided answer:

  • You are missing the head section in the HTML document. It's required for the document to be valid HTML.

  • The provided answer is missing the title tag in the head, which is also required.

  • The Javascript tag should preferrably be in the head section of the document. It works to have script tags in the body, but this is non-standard so it should be avoided if there is no specific reason for it.

  • The script tags have a language attribute which has been deprecated for ages, it only needs the type attribute.

  • You are using the variable i for looping, which is a well known convention. Providing descriptive names for variables is another aspect of good coding, but that doesn't mean that every variable has to have long names. Some variables that are used for an easily recognisable purpose, like loop counters, can have short names.

  • Checking the length of the collection is better than checking for a valid value, it better fits what you actually want to do. Checking for a valid value works in this case, but if you have a collection that could contain null values the loop would stop at the first null value, cutting the loop short.

So, with adding some useful stuff like a doctype declaration (to make the page render in standards mode instead of quirks mode) and a block tag for the content of the page, I would recommend the code to look like this:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
  <title>Links test</title>

  <script type="text/javascript">

  function displayLink() {
    for(var i = 0; i < document.links.length; i++) {
      alert(document.links[i].href);
    }
  }

  </script>

</head>
<body onload="displayLink();">

  <div>
    <a href="http://www.google.com/">First link</a>
    <a href="http://www.yahoo.com/">Second link</a>
    <a href="http://www.msn.com/">Third link</a>
  </div>

</body>
</html>
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • 1
    Thank for so many experts around here!!!!I cannot resist myself to say that you guys really very passionate and helpful!!!!I will read through the comment and advice given later on and make a hard decision on which is the best answer,though I think every give answer is very good!!!!Again Thank you – caramel1995 May 23 '10 at 09:04