From DHTML to DOM Scripting, Part 2

By Christian Heilmann

This chapter is excerpted from Beginning JavaScript with DOM Scripting and Ajax from Apress Publishing.

Visit this page to read the first part of this chapter.

Code Layout

First and foremost, code is there to be converted by the interpreter to make a computer do something--or at least this is a very common myth. The interpreter will swallow the code without a hiccup when the code is valid--however, the real challenge for producing really good code is that a human will be able to edit, debug, amend, or extend it without spending hours trying to figure out what you wanted to achieve. Logical, succinct variable and function names are the first step to make it easier for the maintainer--the next one is proper code layout.

Note If you are really bored, go to any coder forum and drop an absolute like "spaces are better than tabs" or "every curly brace should get a new line." You are very likely to get hundreds of posts that point out the pros and cons of what you claimed. Code layout is a hotly discussed topic. The following examples work nicely for me and seem to be a quite common way of laying out code. It might be a good idea to check whether there are any contradictory standards to follow before joining a multideveloper team on a project and using the ones mentioned here.

Simply check the following code examples; you might not understand now what they do (they present a small function that opens every link that has a CSS class of smallpopup in a new window and adds a message that this is what will happen), but just consider which one would be easier to debug and change?

Without indentation:
function addPopUpLink(){
if(!document.getElementById||!document.createTextNode){return;}
var popupClass='smallpopup';
var popupMessage= '(opens in new window)';
var pop,t;
var as=document.getElementsByTagName('a');
for(var i=0;i<as.length;i++){
t=as[i].className;
if(t&&t.toString().indexOf(popupClass)!=-1){
as[i].appendChild(document.createTextNode(popupMessage));
as[i].onclick=function(){
pop=window.open(this.href,'popup','width=400,height=400');
returnfalse;
}}}}
window.onload=addPopUpLink;
With indentation:
function addPopUpLink(){
  if(!document.getElementById || !document.createTextNode){return;}
  var popupClass='smallpopup';
  var popupMessage= ' (opens in new window)';
  var pop,t;
  var as=document.getElementsByTagName('a');
  for(var i=0;i<as.length;i++){
    t=as[i].className;
    if(t && t.toString().indexOf(popupClass)!=-1){
      as[i].appendChild(popupMessage);
      as[i].onclick=function(){
        pop=window.open(this.href,'popup','width=400,height=400');
        return false;
      }
    }
  }
}
window.onload=addPopUpLink;
With indentation and curly braces on new lines:
  function addPopUpLink()
  {
    if(!document.getElementById || !document.createTextNode){return;}
    var popupClass='smallpopup';
    var popupMessage= ' (opens in new window)';
    var pop,t;
    var as=document.getElementsByTagName('a');
    for(var i=0;i<as.length;i++)
    {
      t=as[i].className;
      if(t && t.toString().indexOf(popupClass)!=-1)
      {
        as[i].appendChild(document.createTextNode(popupMessage));
        as[i].onclick=function()
        {
          pop=window.open(this.href,'popup','width=400,height=400');
          return false;
        }
      }
    }
  }
  window.onload=addPopUpLink;
I think it is rather obvious that indentation is a good idea; however, there is a big debate whether you should indent via tabs or spaces. Personally, I like tabs, mainly because they are easy to delete and less work to type in. Developers that work a lot on very basic (or pretty amazing, if you know all the cryptic keyboard shortcuts) editors like vi or emacs frown upon that, as the tabs might display as very large horizontal gaps. If that is the case, it is not much of a prob-lem to replace all tabs with double spaces with a simple regular expression.

The question of whether the opening curly braces should get a new line or not is another you need to decide for yourself. The benefit of not using a new line is that it is easier to delete erroneous blocks, as they have one line less. The benefit of new lines is that the code does look less crammed. Personally, I keep the opening one on the same line in JavaScript and on a new line in PHP--as these seem to be the standard in those two developer communities.

Another question is line length. Most editors these days will have a line-wrap option that will make sure you don't have to scroll horizontally when you want to see the code. However, not all of them print out the code properly, and there may be a maintainer later on that has no fancy editor like that one. It is therefore a good idea to keep lines short--approximately 80 characters.

Commenting

Commenting is something that only humans benefit from--although in some higher program-ming languages, comments are indexed to generate documentation (one example is the PHP manual, which is at times a bit cryptic for nonprogrammers exactly because of this). While commenting is not a necessity for the code to work--if you use clear names and indent your code, it should be rather self-explanatory--it can speed up debugging immensely. The previ-ous example might make more sense for you with explanatory comments:
/*
  addPopUpLink
  opens the linked document of all links with a certain
  class in a pop-up window and adds a message to the
  link text that there will be a new window
*/
function addPopUpLink(){
  // Check for DOM and leave if it is not supported
  if(!document.getElementById || !document.createTextNode){return;}
  // Assets of the link - the class to find out which link should
  // get the functionality and the message to add to the link text
  var popupClass='smallpopup';
  var popupMessage= ' (opens in new window)';
  // Temporary variables to use in a loop
  var pop,t;
  // Get all links in the document
  var as=document.getElementsByTagName('a');
  // Loop over all links
  for(var i=0;i<as.length;i++)
  {
    t=as[i].className;
    // Check if the link has a class and the class is the right one
    if(t && t.toString().indexOf(popupClass)!=-1)
    {
      // Add the message
      as[i].appendChild(document.createTextNode(popupMessage));
      // Assign a function when the user clicks the link
      as[i].onclick=function()
      {
        // Open a new window with
        pop=window.open(this.href,'popup','width=400,height=400');
        // Don't follow the link (otherwise the linked document
        // would be opened in the pop-up and the document).
        return false;
      }
    }
  }
}
window.onload=addPopUpLink;
A lot easier to grasp, isn't it? It is also overkill. An example like this can be used in training documentation or a self-training course, but it is a bit much in a final product--moderation is always the key when it comes to commenting. In most cases, it is enough to explain what something does and what can be changed.
/*
  addPopUpLink
  opens the linked document of all links with a certain
  class in a pop-up window and adds a message to the
  link text that there will be a new window
*/
function addPopUpLink()
{
  if(!document.getElementById || !document.createTextNode){return;}
  // Assets of the link - the class to find out which link should
  // get the functionality and the message to add to the link text
  var popupClass='smallpopup';
  var popupMessage=document.createTextNode(' (opens in new window)');
  var pop,t;
  var as=document.getElementsByTagName('a');
  for(var i=0;i<as.length;i++)
  {
    t=as[i].className;
    if(t && t.toString().indexOf(popupClass)!=-1)
    {
      as[i].appendChild(popupMessage);
      as[i].onclick=function()
      {
        pop=window.open(this.href,'popup','width=400,height=400');
        return false;
      }
    }
  }
}
window.onload=addPopUpLink;
These comments make it easy to grasp what the whole function does and to find the spot where you can change some of the settings. This makes quick changes easier--changes in functionality would need the maintainer to analyze your code more closely anyway.

Functions

Functions are reusable blocks of code and are an integral part of most programs today, including those written in JavaScript. Imagine you have to do a calculation or need a certain conditional check over and over again. You could copy and paste the same lines of code where necessary; however, it is much more efficient to use a function.

Functions can get values as parameters (sometimes called arguments) and can return values after they finished testing and changing what has been given to them. You create a function by using the function keyword followed by the function name and the parameters separated by commas inside parentheses:

function createLink(linkTarget, LinkName)
{
  // Code
}
There is no limit as to how many parameters a function can have, but it is a good idea not to use too many, as it can become rather confusing. If you check some DHTML code, you can find functions with 20 parameters or more, and remembering their order when calling those in other functions will make you almost wish to simply write the whole thing from scratch. When you do that, it is a good idea to remember that too many parameters mean a lot more maintenance work and make debugging a lot harder than it should be.

Unlike PHP, JavaScript has no option to preset the parameters should they not be available. You can work around this issue with some if conditions that check whether the parameter is null (which means "nothing, not even 0" in interpreter speak):

function createLink(linkTarget, LinkName)
{
  if (linkTarget == null)
  {
    linkTarget = '#';
  }
  if (linkName == null)
  {
    linkName = 'dummy';
  }
}
Functions report back what they have done via the return keyword. If a function that's invoked by an event handler returns the Boolean value false, then the sequence of events that is normally triggered by the event gets stopped. This is very handy when you want to apply functions to links and stop the browser from navigating to the link's href. We also used this in the "Object Detection vs. Browser Dependence" section. Any other value following the return statement will be sent back to the calling code. Let's change our createLink function to create a link and return it once the function has finished creating it.
function createLink(linkTarget,linkName)
{
  if (linkTarget == null) { linkTarget = '#'; }
  if (linkName == null) { linkName = 'dummy'; }
  var tempLink=document.createElement('a');
  tempLink.setAttribute('href',linkTarget);
  tempLink.appendChild(document.createTextNode(linkName));
  return tempLink;
}
Another function could take these generated links and append them to an element. If there is no element ID defined, it should append the link to the body of the document.
function appendLink(sourceLink,elementId)
{
  var element=false;
  if (elementId==null || !document.getElementById(elementId))
  {
    element=document.body;
  }
  if(!element) {
    element=document.getElementById(elementId);
  }
  element.appendChild(sourceLink);
}
Now, to use both these functions, we can have another one call them with appropriate parameters:
function linksInit()
{
  if (!document.getElementById || !document.createTextNode) { return; }
  var openLink=createLink('#','open');
  appendLink(openLink);
  var closeLink=createLink('closed.html','close');
  appendLink(closeLink,'main');
}



Page 1 of 2

 
1 2
Next Page

Make a Comment

Loading Comments...

  • Web Development Newsletter Signup

    Invalid email
    You have successfuly registered to our newsletter.
  •  
  •