9781430237891_CO-01.jpg

Chapter 9

A Deeper Dive Into JavaScript

Now that we can construct more complex logic with loops and conditional statements, let’s take our knowledge of JavaScript to the next level.

In this chapter, we’ll cover some of the more advanced concepts in JavaScript. For example, we’ll look at object-oriented design—from the strategy of why you would use objects to the tactics of how you would use them. Understanding object-oriented design is a vital skillset that will apply to most other languages that you will learn.

We’ll also learn about functions, from introductory concepts such as how to construct a function to advanced concepts like lambda calculus, or the art of using functions as variables. Using functions as variables is a key concept in functional programming, which is a very fluid and extensible programming philosophy that is embodied in other languages like Scala, Clojure, and Lisp.

Next, we’ll talk about events, the glue that allows your code to react to actions taken by the user. And finally, we’ll look at interacting with the DOM—the API that the browser exposes to JavaScript to interact with HTML elements on the page—and tying everything that we’ve learned so far into a comprehensive example.

Philosophy of object-oriented design

When talking about objects, the first question we need to address is this: what are objects? At an abstract level, objects are metaphors that represent ideas.

Maybe these are metaphors for high-level business concepts like the idea of a user of a system. Or perhaps these are metaphors for the parts of a system, like a directory watcher. Whatever idea they represent, objects should encompass everything about the concept, including what defines the idea (values of properties) and what the concept does (methods of the object).

For example, if an object represents a user, then the properties of the user are things that define the user. Consider what happens when you fill out a registration form online. You usually enter your name, email address, a password, and maybe your street address. These are all properties that define you in a given system.

Continuing with the same analogy, methods are actions that a user can make. In the case of an online shopping cart, a user could add an item to her cart. Or, a user could log in and out of the site. Those are all actions—represented by methods—that a user can take.

But at its most concrete level, an object is a collection of functions (i.e., methods in the context of objects) and variables (i.e., properties in the context of objects).

Why would we want to use objects? Objects allow us to encapsulate all of the information that pertains to a given idea in one neat and easy-to-understand variable. They allow us to construct the logic of our applications using the language and terminology of business cases.

In JavaScript, we can create objects a couple different ways:

  • Using an object constructor
  • Using object notation

Object constructor

The first way we will explore creating objects is with an object constructor. Object constructors are functions (and we will explore functions in much more depth in the next section) that accept parameters and populate the properties of the object with the passed in values. We instantiate new objects from object constructors with the new keyword:

 <script>

  function user(fname, lname, emailaddress){

  this.firstname = fname;

  this.lastname = lname;

  this.email = emailaddress;

  }

  var tom = new user("tom", "barker", "[email protected]")

 </script>

In the preceding example, we created a new object constructor called user that accepted three parameters:

  • first name (fname)
  • last name (lname)
  • email address (emailaddress)

Note that the property names are firstname, lastname, and email, yet the variables defined in the signature of the function are fname, lname, and emailaddress. This is because these are different variables. The properties are variables that are referenced through the object (user.firstname), but the variables in the signature are parameters, and we don’t want to mix up the two. We will talk more about parameters later in the chapter.

The constructor took those passed in values and stored them in variables. Note that the variables are scoped using the this keyword. The this keyword exposes the variables as properties of the object; if we didn’t use that keyword, we would not see the values stored when we create an object from the constructor.

To create a new object, we simply create a new variable. For example, we might create a tom object and assign to it the object constructor. This creates a new object named tom with its properties set to the values we pass into the constructor.

We can access the properties and methods of the object using dot notation. This means that we reference properties and methods like [object name].[object property]. So, for the preceding example, we could use this syntax to access the firstname property of the tom object:

 <script>

 log(tom.firstname);

 </script>

But objects also have methods, so let’s update this example to give the user object some actions to perform:

 <script>

  function user(fname,lname, emailaddress){

    this.firstname = fname;

    this.lastname = lname;

    this.email = emailaddress;

    this.whoami = function(){

      alert(this.fname);

    };

  }

  var tom = new user("tom", "barker", "[email protected]")

  tom.whoami();

 </script>

In the preceding example, we added the whoami() method to the constructor—again, note that it is prefaced with the this keyword. Once again, we access the whoami() method via dot notation.

Object notation

Another way to create objects in JavaScript is with straight object notation. When creating an object via object notation, objects are wrapped in curly braces, and methods and properties are comma-separated name-value pairs. This is also called creating an object literal. To reproduce the preceding functionality with object notation, we would do the following:

 <script>

 var newuser = {

  firstname: "tom",

  lastname: "barker",

  email: "[email protected]",

  whoami: function(){

    console.log(this)

  };

 }

 newuser.whoami();

 </script>

Inheritance

You gain many benefits by using objects. Objects encapsulate all of the data and functionality associated with a given concept, which saves you the trouble of keeping track of and associating many disparate variables. This wraps all of the relevant information about a given subject and allows you to check and update that information in a single variable. It also allows you to reuse that aggregation and structure to create subclasses.

You can also create subclasses from existing classes that derive their functionality from the original object, but allow you to expand on that functionality for different use cases. This is called inheritance.

What does this mean, exactly? Let’s take a closer look at the preceding example. We created a user object that contained the first name, last name, and email address of a user. The user object also had a method called whoami that output the object to the console (assuming Firebug is installed; learn more about Firebug in Chapter 10).

But let’s say we want to create a special user—a super user—who can modify other users. We could create a new object called admin that is derived from the user object, as in this example:

 <script>

  function user(fname,lname, emailaddress){

    this.firstname = fname;

    this.lastname = lname;

    this.email = emailaddress;

    this.whoami = function(){

     alert(this.fname);

    };

  }

  function admin(){

  //do some initialization here

  };

  admin.prototype = new user;

  admin.prototype.constructor = admin

  admin.prototype.editUser = function(usr){

   //update user properties or permissions

   console.log("editing properties of " + usr.firstname)

  };

  var su = new admin();

  su.whoami(); //shows object in object notation

  su.editUser(tom) // assumes that object tom from previous example exists

 </script>

Now let’s carefully walk through the preceding example.

First, we created a constructor function called admin. Note that we didn’t include any parameters when we created the admin constructor. This is purely because, in this example, we just created a stub for the admin constructor; it has no real functionality in this case. However, depending on what we want it to do, we could pass in arguments that will initialize properties on startup, just as we did with the user constructor. We could then set the prototype of admin to be the user object.

This is a key part of the philosophy behind JavaScript: it is a prototype-based language. What this means at a tactical level is that objects can be linked together via their prototype property, forming a prototype chain. When you reference a method or a property of an object, and it doesn’t explicitly have that property or method defined, it looks to its prototype property to see whether the object stored there has that property or method. And this searching up the chain continues until one of the objects has the property or method—or until JavaScript reaches the top of the chain, at the Object object. The Object object sits at the very top of the prototype chain, and it is the base object that all objects in JavaScript inherit from (see Figure 9-1).

9781430237891_Fig09-01.jpg

Figure 9-1. The JavaScript prototype chain

What that means for our example is that, by making the user object the prototype of the admin object, we can then call methods or properties of the user object from the admin object.

So, after we set the prototype of the admin object, we then set the constructor property of the admin object to be the admin constructor. Doing this ensures that any instances we create are of the admin type.

Next, we create a new method called editUser(). This method exists only in the admin object, not the user object. In this way, we have extended the user object to create a special user—admin—that has augmented functionality.

We can see this in action by calling the whoami() method of admin; which works the same way as the user object.

Functions

Functions are a way to meaningfully aggregate and name expressions. By giving a function a name, we can invoke the function by its name, and it will execute all of the expressions that it contains. Functions are structured as follows:

 function [function name] (){

 //expressions to execute

 }

We can name functions just as we would name any other variable. For example, assume we wanted to have a function that messaged the user. We might make something like this:

 <script>

 function messageUser(){

  alert("hello, world!");

 }

 </script>

This creates a function called messageUser. Every time we call the function, it pops open an alert with the string, “hello, world.” We invoke the function by calling its name, followed by open and closed parentheses:

  messageUser();

Parameters and arguments

By itself, this approach would only be so useful; however, we can also pass data in to be used by the function. When creating a function, we can allow for one or more arguments to be passed into the function. The data from these arguments are temporarily stored as parameters, which are local variables in a function that exist only as long as the function is running. It would be structured as follows:

 <script>

  function msgUser(msg){

    // now do an alert, using the string passed in and stored in the parameter msg

    alert(msg);

 }

 msgUser(“hello, world!”);

 </script>

When we invoke a function, we pass in data (one or more arguments) to be stored in the parameter(s). To be clear, when we call the function, the data being passed in is called the argument. When the function is defined, the local variable that is created to hold the passed in data is called the parameter.

So, in the preceding example, the msg variable in the function signature is the parameter, and the “hello, world” string is the argument being passed into the function.

Pardon the tangent—I’m sick of writing alerts! In real production code, we never pop open alerts to the end user. So, for the next example, let’s create a log function. This will be a function to which we pass in a string, and it will write that string to a div on the page, followed by a line break. From this point on, all of our examples where we want to display data will use our log function. The log function assumes that a div with the id of log exists on the page:

 <body>

 <div id="log"></div>

 <script>

 function log(msg){

  document.getElementById("log").innerHTML += msg + "<br/>";

 }

 log("hello, world!"); // invoking the function, passing in the string hello, world

 </script>

 </body>

Return values

Functions also return values. In strictly typed languages, functions are declared with a return type. Even when there is no value returned, we would need to declare that as a void type. But since JavaScript is loosely typed, we don’t have to worry about that.

We use the return keyword to exit the function with a returned value.

Return values allow functions to output the result of their processing. This output can be stored in variables or tested in conditions.

In the next example, we create two functions, one called sum and one called avg. The function called sum receives an array as a parameter, loops through the array, and adds up the values it contains (only if the value at a particular index is a number). Finally, it returns the total.

The function called avg also receives an array; calls the sum function passing in the array; stores the value returned from sum; and finally, returns that total from sum divided by the length of the array, which is the average value in the array:

 <script>

 function sum(vals){

  var summed_value = 0;

  for(var x = 0; x < vals.length; x++){

  summed_value += vals[x];

  }

  return(summed_value);

 }

 function avg(vals){

  var total = sum(vals);

  return(total / vals.length);

 }

 var test_scores = [90, 94, 88, 56, 100, 81];

 var grade = avg(test_scores);

 </script>

Note that using the return keyword does more than return a value; it also exits the function. If you load up your function with many different return paths—for example, if you have multiple if statements where each branch returns a different value—then you will have a harder time debugging your application. It’s generally a best practice to have only one way to exit your functions. If you do have multiple if statements, you should set a variable in the body of the if statements and then return the variable after the if statements, as in this example:

 <script>

 function dosomething(){

  var returnValue = 0;

  if(somecondition){

   returnValue = 1;

  }else{

   returnValue = 2;

  }

   return returnValue;

 }

 </script>

Functions as first class objects

In the last chapter, we said that functions are a data type. That’s a hugely important point to effectively use some of the more interesting features of JavaScript. While we can store return values from functions, those return values are of the type that is returned. In the preceding example, both sum and avg return numbers.

But we can also store the functions themselves in variables! This means that we can pass functions into other functions and return functions from functions. This is what is meant when we say that functions are first-class objects, and this opens up a huge amount of things that we can do with functions.

Again, consider the previous example with the avg and sum functions, but this time assume we will be a professor who wants to create a script to calculate semester grades based on input test scores. As a professor, we will want to change our business logic to drop the lowest grade from the semester, as in the following example:

 <script>

 var LOGIC_TO_USE = "adjusted",

  semester_data = {

  test_scores:[90, 94, 88, 56, 100, 81],

  total:0,

  grade:0

 };

 if(LOGIC_TO_USE === "adjusted"){

  avg(semester_data, sum_drop_lowest); // this will return average

  // based on dropping the lowest score

 }else{

  avg(semester_data, sum); // this will return average of all test scores

 }

 log(semester_data.grade);

 //this begins the engine that drives the business logic

 function sum(semester_object){

 for(var x = 0; x < semester_object.test_scores.length; x++){

  if(typeof semester_object.test_scores[x] == "number"){

  semester_object.total += semester_object.test_scores[x];

 }

  }

  return(semester_object);

 }

 function avg(semester_object, sum_function){

  semester_object = sum_function(semester_object);

  semester_object.grade = semester_object.total/ semester_object.test_scores.length;

  return(semester_object);

 }

 function sum_drop_lowest(semester_object){

  semester_object.test_scores = semester_object.test_scores.sort(function(a,b){return a - b});

  semester_object.test_scores = semester_object.test_scores.slice(1,image

  semester_object.test_scores.length)

  for(var x = 0; x < semester_object.test_scores.length; x++){

   if(typeof semester_object.test_scores[x] == "number"){

   semester_object.total += semester_object.test_scores[x];

 }

  }

  return(semester_object);

 }

 </script>

OK, this is a fair bit of refactoring; however, don’t be intimidated because we’ll walk through the example a little at a time. First, we created an object to aggregate the semester data, so that we could pass it around and not have the functions dependent on each other. The semester object has test_scores, total, and grade as its properties. We can access these properties via dot notation, such as obj.grade and obj.total.

Next, we created three functions. We’ve already seen the function sum. In this case, we just updated the function to use the object that holds the array; instead of returning the sum, the function updates the total in the object and returns the object.

Next, we created a new function, sum_drop_lowest. This function takes the array of grades out of the object and sorts it. Notice that we pass a function into the sort method. Doing so makes JavaScript’s native sort functionality call the passed function for each index and evaluate the index’s values as parameters. This gives us a numerically sorted array. With this newly sorted array, we use the slice method to take a subsection of the array from the second to the last index (technically, it’s index 1 because arrays are zero-based). This effectively drops the first value because that is the lowest grade. The function then returns the object.

And finally, we updated the avg function, which now accepts two parameters: the object and a function to sum the grades. Depending on what we pass into the avg function, it will do different things. If we pass in the regular sum function, it will work as it did before, giving us a result of 84.8; however, if we pass in the sum_drop_lowest function that drops the lowest grade, the avg function will give us a result of 90.6.

We created a variable called LOGIC_TO_USE that we will treat as a constant—the const keyword does exist, but it isn’t yet supported by IE, so we’ll continue to use var. Constants are variables that cannot have their value changed once they are declared. We test the value of this faux constant and pass in the appropriate function to the avg function.

Anonymous functions

JavaScript supports anonymous functions, which are functions that don’t have assigned names. Anonymous functions can be assigned to variables, returned from functions (most likely to be stored in a variable), stored (in a property) as a callback function, or be a self-invoking function, usually to namespace variables on a page (see the next section).

Anonymous functions are typically formatted as follows:

 function(){

 //code to execute

 }

When storing them in a variable, you would format them like this:

 var func = function(){

  //code to execute

 }

If you store the function in a variable (or property of an object, or pass around as a parameter), you can invoke the function using the variable name as if the function had a name, as in this example:

 func();

When returning an anonymous function from a function, you would format it like this:

 function x(){

  return function(){

  //code in the returned anonymous function

  }

 }

To store and execute a returned anonymous function in a variable, you would do the following:

 function returnAnonFunc(){

  return function(){ // returned anonymous function

  alert("anonymous function!")

  };

 }

 var f = returnAnonFunc(); // anonymous function stored in this variable

 f(); //we can invoke the stored anonymous function

Self-invoking functions

Self-invoking functions are functions that are executed as soon as they are defined. They are formatted the same as any other anonymous function, except that they are followed by open and closed parentheses:

 function (){

  //code to execute

 }();

You might wonder why you would ever want to use a self-invoking function because code defined at the root level of the script tag automatically executes anyway. The answer: Such a function limits the scope of the variables and functions that you define. Let me explain:

A variable that is defined at the root of the script tag (or outside of a function or object) will be placed in the global scope; this is called a global variable. Such a variable is available everywhere in the current page, and it can be accessed by code in other script tags or code imported externally. Most importantly, a global variable can accidentally be overwritten by the code in other script tags, as well as by the code imported externally.

To demonstrate why this is dangerous, consider the following scenario.

Assume you have ad tags on your site that allow JavaScript to be included on your page from a third-party ad server. You have a function that you have written called log() that logs errors and other issues to your server for analysis. Your log() function exists at the global scope because you defined it at the root of a script tag on your page.

The ad code that is running on your page also has a log() function, which it uses to report back to the ad server that the ad has been displayed, so you can be paid for this ad view. The ad code’s log() function also exists at the global scope.

If your code is loaded and interpreted first, then the ad code will overwrite your log() function when it is loaded, and you’ll never get the messaging on your server for that page load. At the same time, you’ll be making fraudulent ad calls to the ad server and that could have legal and financial repercussions for your company. If the ad code loads first, then you will overwrite it when your code loads, the ad impression will never be recorded, and you won’t be paid by the ad company for that page load.

And if other functions or objects depend on the log() function, the repercussions could just ripple outward.

Fortunately, we have a work around for this: namespacing.

Variables that are defined within functions are locally scoped, which means that they exist only as long as the function is running and can only be accessed by code within the function. Once the function runs to completion, the variable is destroyed and the space in memory allocated to it is scheduled for garbage collection. This is called local scope.

However, through a concept called a closure, we can bind the locally declared variables and functions to a returned object, as in this example:

 <script>

 var myPage = function(){

  return {

   log : function(){

    //logs data to my server

   }

  };

 }();

 </script>

In the preceding example, we declared a variable called myPage. This variable holds the returned object from the anonymous function. This is our namespace, and it protects all of the functions and variables that we will write for our page or web application. To invoke the log() function (or any other function that we will namespace), we go through the myPage object, like so:

 myPage.log();

If we want to take the preceding example a step further, we can create variables and functions inside the anonymous function (but not inside of the returned object), and these variable and functions will be accessible to the returned object, but not anywhere else:

 <script>

 var myPage = function(){

 var runtime = "production"; //locally scoped

 function _logtopage(msg){ //privately scoped

  //writes msg to page

 }

 function _logtoserver(msg){ //privately scoped

 //sends msg to server

 }

 return {

   log : function(msg){

  if (runtime === "production"){

    _logtoserver(msg);

  }else{

     _logtopage(msg);

  }

 }

 };

 }();

 </script>

In this code snippet, we created a namespace called myPage that has an exposed log() method. The log() method will either send a message to the server or write to the page, depending on the value of the runtime variable.

This example illustrates how the runtime variable and the _logtopage() and _logtoserver() functions are locally scoped inside the anonymous function. However, they are accessible to the function inside the returned object. This is a closure, as described previously; it is the context that keeps the locally scoped variables available to the functions that were created in the same context—the anonymous function, in this example.

Events

Events are actions that occur during the lifetime of the page. These can be actions that the end user fires off by clicking a button or moving the mouse, or they can be caused by other DOM- or UI-related actions. They can also be actions that happen on the page (e.g., the document loading) or on the network (e.g., the HTTP status changing in an Ajax call). Chapter 10 discusses Ajax in greater depth.

JavaScript responds to events with event handlers, or functions that are called when an event is fired. Event handlers can be called by name or defined as function literals.

When binding an event to a DOM element—remember that the DOM is the API through which the browser allows JavaScript to access the HTML elements on the page—you can include the event handler in the DOM element referenced in the event attribute. It is structured like this:

 <element [event attribute] = "[javascript function]"/>

A more specific example would involve adding the onmousemove event attribute to a div to fire an event every time the mouse moves over the div. That would look like this:

 <div onmousemove = "trapMouse()"></div>

Now let’s flesh this idea out with a longer and more involved example:

 <body>

 <div id="content" onmousemove="trapMouse(event)">

 <p>Show the mouse location.</p>

 <div id="log"></div>

 <script>

 function trapMouse(event){

  log("mouse X: " + event.clientX + " mouse Y: " + event.clientY)

 }

 function log(msg){

  document.getElementById("log").innerHTML += msg + "<br/>";

 }

 </script>

 </div>

 </body>

In the preceding example, we added the onmousemove event attribute to the content div. The onmousemove event attribute points to the trapMouse() function. It passes in a reference to the event that was fired in the form of an event object.

The trapMouse() function receives the event object and calls our existing log() function, passing in a string that contains the x and y coordinates of the current mouse location.

The downside to using event attributes inline in your HTML is that you have now coupled your functionality with your presentation. To make your code more flexible, you can programmatically assign event handlers to elements.

The next example has two files. The first is an HTML file (chapter9_example.html) that contains only the layout of the page (see Listing 9-1), and the second is a JavaScript file (chpt9_engine.js) that contains the functionality; make sure that these files are in the same directory (see Listing 9-2).

Listing 9-1. The Page Layout File 

<html>

<head></head>

<style>

#content{

   border:2px solid;

}

</style>

<body>

   <div id="content"></div>

   <div id="log"></div>

   <script src="chpt9_engine.js"></script>

</body>

</html>

Listing 9-2. The JavaScript File that Contains the Functionality

var myApp = function(){

  return{

   log:function(msg){

    document.getElementById("log").innerHTML += msg + "<br/>";

  },

   registerEventHandlers:function(){

    document.getElementById("content").onmousemove = function(){

     myApp.log("mouse moving!")

    }

  }

};

}();

myApp.registerEventHandlers();

In the preceding example, we pulled together a lot of what we’ve been talking about. We created a self-executing anonymous function to namespace all of the objects on the page. The namespace is called myApp. The myApp object has a function called registerEventHandlers() that assigns an anonymous function to the onmousemove event of the element on the page that has an id of content.

The beauty of this method is that we can apply this to whatever HTML page we want, and it will work, as long as the page has an element with an id of content.

For a full listing of events and what each event is, see the W3C’s list of events here at www.w3.org/TR/DOM-Level-3-Events.

Interacting with the DOM

At this point, we have a much better grasp of JavaScript, so let’s start to add some scripting to the running example that we’ve been working with. The first thing we want to do is to create an external JavaScript file that our Summer Slam form will link to. We’ll call the file javascript.js, and we’ll put it in the js directory.

Let’s start by creating a namespace. First, we create an object called summerSlam that is returned from a self-executing function. In this object, we create a method called formValidate(). For now, this method just pops up an alert; this is so that we can make sure that we are linking to the .js file, creating the object, and invoking the method without issue. It’s always best to make sure your code is wired up correctly before you start layering in the functionality because it will only get harder to debug any issues as you add more code:

var summerSlam = function(){

  return{

    formValidate: function(form){

        alert("hello there");

        return false;

    }

  };

 }();

To test this, we can update the form element in the HTML page:

 <form action="/registration/" onsubmit="return summerSlam.formValidate(this);">

So far, we have hooked into the onsubmit event in the form and invoked the formValidate() method of the summerSlam object.

There are a couple of things to note here. First, we pass this to the formValidate() event handler; in this context, the this keyword refers to the form element and gives our JavaScript direct access to the elements in the form and their values.

The other thing to notice is that, in the event handler, we are specifically returning the result of the formValidate() function. If we have formValidate() return false, then this cancels any further submission of the form; however, if it returns true, then the form will successfully submit.

If we’ve successfully wired everything up correctly, then filling out the form and hitting submit should raise an alert. The next step is to actually do something on hitting submit.

We have some very cool HTML5 validation in the form elements to make sure that they are filled in; however, let’s code some JavaScript fallbacks, just in case our end user has a browser that doesn’t support that feature.

Let’s start by updating formValidate(). First, we will create an array to hold the ids of all of the fields that are required fields:

 var requiredFields = ["name", "email", "party" ]

Next, we’ll loop through all of the form’s elements via the passed in data from the form object. They are stored as an array in the elements property:

 for(var x = 0; x < form.elements.length; x++){

 }

For efficiency’s sake, we’ll make sure that we only reference elements that are in our required list. To do that, we make an if statement that, as we loop through the form elements, checks with the indexOf() method to see if each element is in our array of required fields. The indexOf() method returns an index number that you can use to find the value you are searching for. If the array does not contain that value, then indexOf() returns a value of -1.

 if(requiredFields.indexOf(form.elements[x].id)>-1){

 }

Within that if block, we’ll then test whether the element has any sort of value assigned to it. We’re pretty much just interested only in the text boxes in the form, so we’ll test the value property—that’s where the data that gets typed into the text box gets stored. We’ll test whether the value property has no value or has an empty string for a value. If either of those conditions are true, then we’ll send the user back to the input element in question by calling the focus() method of that element. Next, we’ll instruct the user to please complete all of the required fields; and finally, we’ll return the value, false.

You may remember how, in the event attribute, we set onsubmit to be the return value of this function call. Thus, returning false from the function prevents the form from submitting:

 if((form.elements[x].value.length <=0) || (form.elements[x].value == " ") ){

 form.elements[x].focus()

  alert("please complete all required fields")

  return false;

 }

If we put all of this together, we can have the following code populate our javascript.js file:

formValidate: function(form){

  var requiredFields = ["name", "email", "party" ]

  for(var x = 0; x < form.elements.length; x++){

  if(requiredFields.indexOf(form.elements[x].id)>-1){

   if((form.elements[x].value.length <=0) || (form.elements[x].value == " ") ){

    form.elements[x].focus()

    alert("please complete all required fields")

    return false;

   }

  }

 }

}

Summary

We covered a lot of material in this chapter. For example, we explored the philosophy behind object-oriented design; how to create objects; and most importantly, why we would want to. Furthermore, we explored the idea of inheritance and saw how JavaScript uses prototypes to allow the creation of objects that are derived from other objects.

We also explored functions and got a taste of the flexible beauty that functional programming allows by treating functions as a first-class object that can be passed around. We also interacted with the DOM to do form validation.

Most importantly, we can now think about implementing more complex logic in JavaScript, and we should be able to solve problems with the language that we may not have been able to before.

But this is just the beginning—take what you’ve learned this chapter and play with the ideas. Write your own scripts to test the limits of what you think you can do with the language. I frequently challenge my own students to create applications of their own design and present them to the class, just so that they can demonstrate how they can think in the language. I now ask the same of you. Practice and play with the ideas until they make complete sense in your mind.

And when you are ready, proceed to the next chapter, where we will explore additional concepts like storing data with cookies or local storage, loading external data with AJAX, using debugging tools, and introducing test-driven methodology to our JavaScript development!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset