More Concepts and Best Practices - Getting Good with JavaScript (2011)

Getting Good with JavaScript (2011)

More Concepts and Best Practices

You now have a good grasp of the basics of JavaScript. This chapter will take that knowledge up a level: we'll discuss some of the more complex JavaScript features, as well as some good practices for coding. So let's not waste another moment!

this

The first this we're going to tackle is this. Wait, what? That's right: this. It's rather hard to talk about, because of the name, but it's an important concept to understand. This is a keyword in JavaScript that you can think of as a dynamic variable that you can't control. The value of thischanges based entirely on where you are in the code. Let's take a look.

For the majority of your code, this will reference the global object. I've mentioned the global object very briefly, but now is a good time to get to know it better. Remember the parseInt and parseFloat functions we talked near the end of the last chapter? These are functions are actually methods of the global object. This means you can access them via this format:

Example 4.1

alert( this.parseInt("10.2", 10) ); // 10

alert( this.parseFloat("3.14159") ); // 3.14159

Here's a general rule: unless you've done something to change the value of this, it refers to the global object. When this is the case, anything you'd access without specifying an object is a property of the global object. Yes, this even applies to global-level functions and variables of your own. Try this:

Example 4.2

var my_variable = "value";

function my_function () { return "another_value" }

alert( this.my_variable ); // "value"

alert( this.my_function() ); // "another_value"

this doesn't really have a proper name, but it does have a property that refers to itself: window. If you could see this code, it might look something like the following:

var global = {

window : global

. . .

};

this = global;

This means you can also access your variables and functions as properties of window, which is more common than using this. It gets a bit more confusing here, because you can access window to use things on the global object even when this refers to something else. Even then, you don't have to call it off window, unless you have a local variable or function overwriting it.

Now that we've (somewhat) got a hold on what this is by default, let's look as how we can change it.

The new Keyword

The first way of changing this that we'll look at is yet another keyword: new. But first, some context.

You know what a JavaScript object is. Keeping most of your related functionality in an appropriate object and accessing it via an appropriate interface is a very (very, very) basic description of what's called "Object-Oriented Programming" (OOP). Many programming languages use classes to do OOP. Classes are like blueprints: they aren't the real objects, but they lay out what the objects will have when they are created. JavaScript is very object-oriented, but it doesn't use classes. Instead, it uses prototypes. Prototypes are real objects (the same objects you've already seen), and we can use them as a "living" blueprint for other objects.

With all that said, let's get back to new. The classes in other languages use constructor functions to construct the new objects. In JavaScript, constructors are regular functions, written to create new object and called with the keyword new in front of them. Let's take a look at how to write and call this type of function.

Let's say we want to create truck objects. I know: this isn't necessarily practical. You probably won't ever need truck objects in JavaScript, but it's something you'll be familiar with while we discuss new and it's crew.

So, here's a function that will create a truck:

Example 4.3

function Truck(model) {

this.num_of_tires = 4;

this.kilometers = 0;

this.model = model;

}

var my_truck = new Truck("Hercules");

console.log(my_truck);

Notice two things here: first, we're defining all these variables as properties of the object this. Second, we don't return anything from this function. Both of these are because we plan to call this function with the new keyword. At the end there, you can see how we call this function.

Take note of how we use new here. This does two things to the function. First, it changes this to a new clean object. Obviously, we then add our custom properties within the function. The second thing new does is assure that this is returned. Now the value of my_truck is just the same as if we had done this:

Example 4.4

var my_truck = {

num_of_tires : 4,

kilometers : 0,

model : "Hercules"

};

console.log(my_truck);

That's the idea of using new: we get a super easy way to create objects. Obviously, you won't use this when you just need one or two simple objects. It's most useful when you have a lot of functionality to pack into an object, or you want to create a lot of similar objects.

We'll come back to new a bit later. For now, let's discuss the other ways to change this.

call and apply

I mentioned earlier that everything in JavaScript is an object—even functions. Since functions are objects, they can have properties and methods. call and apply are two methods that functions have by default.

The only reason for these functions to exist is to change the value of this within the function. Let's see how to do it.

Example 4.5

function Truck (model, num_of_tires) {

this.num_of_tires = num_of_tires;

this.kilometers = 0;

this.model = model;

}

var basic_vehicle = { year : 2011 };

Truck.call(basic_vehicle, "Speedio", 4);

console.log(basic_vehicle);

Here, we're calling the Truck function via it's call method. The first parameter of call is the object we want to be considered this within the function. Since we're not using new with this call to Truck, it doesn't create a new object or return this by default. That's what we want in this case, because we're modifying an existing object.

ROCKSTAR TIP

An aside on primitive vs. reference values: You might think that, although we're modifying an existing object, we will lose those changes unless we assign them to a new variable, or back to basic_vehicle. That would be the case if our variable was a primitive value. However, objects (and arrays) are reference values: values passed by reference. A primitive value (such as a string or number) is stored in a spot in your computer's RAM, and we keep track of it with a variable. When we pass that variable to a function, we copy that value to a new spot in memory, point the parameter name to that spot, and work with that inside the function, so that the original is unharmed. It's different with reference values: when we pass an object or array to a function, the parameter points to the very same spot in memory as the original variable. This means that thethis inside Truck.call(basic_vehicle) is the very same basic_object we have outside the function. So there's no need to assign anything, because basic_vehicle now has the properties assigned by Truck. What would happen if we assigned the returned value ofTruck.call(basic_vehicle) to a variable? It would be undefined, because Truck without new doesn't return anything.

After the object that will be this (you could call this the context of the function), we can pass in any parameters necessary. These will be passed to the function being executed. As you can see in our above example, the second parameter "Speedio" is being passed to Truck as its first parameter. The third parameter 6 becomes the second parameter of Truck. Of course, this will work for as many parameters as you required

There's an alternate form of call, named apply. The difference here is that apply takes only two parameters. The first is the context object. The second is an array of parameters that will be passed to the function. This is useful if you have the parameters as an array, instead of as loose variables. For example, let's say we ask the user to enter the model of the truck and the number of wheels it has into a textbox. The string user_input represents what we may have gotten back from them:

Example 4.6

function Truck (model, num_of_tires) {

this.num_of_tires = num_of_tires;

this.kilometers = 0;

this.model = model;

}

var basic_vehicle = { year : 2011 },

user_input = "Speedio 18";

Truck.apply(basic_vehicle, user_input.split(" "));

console.log(basic_vehicle);

This is a great place to use apply. We call split on that input string and split it on a single space character; this returns an array that would look like this: ["Speedio", "18"]. If we were going to use Truck.call here, we would cache that array in a variable and pass the its elements individually. like this:

var user_array = user_input.split(" ");

Truck.call(basic_vehicle, user_array[0], user_array[1]);

Obviously, this is more work; so we can just pass that array to apply, and it will assign the elements of the array to the parameters of the function we're applying it to in order.

If you're like me, and have a hard time remembering whether it's call or apply that takes the array, then notice that array and apply both start with a (and end with "y", and have a double consonant, if that's any help).

Inside an Object

Okay, there's one more way to change the value of this. We've talked about object literals enough that you're familiar with them. Well, remember that we can use functions as the value of a property—a method, it's usually called. Check this out:

var waitress = {

name : "Ashley",

greet: function (customer) {

customer = customer || " there!";

return "Hi" + customter + " My name is Ashley; what can I get you?";

}

};

Behold a waitress object; nothing too complicated is going on here; she's got a name and a greet function. However, what would happen if we ran this:

waitress.name = "Melissa";

That resets her name property; but she'll still be greeting people by calling herself Ashley! That won't do; but how can we reference the name property of the object?

It won't be obvious that we need to change that return message to this:

return "Hi" + customter + " My name is " + this.name + "; what can I get you?";

The million dollar question is, why do we do it that way? Let's step through what you're probably thinking. Your first thought might be to use name as a variable and just put it in there, but since it's a property, that doesn't work. Next, you might try this:

return "Hi" + customer + " My name is " + waitress.name + "; what can I get you?";

Yes, that works, but the problem here is that we could do this:

Example 4.7

var waitress = {

name : "Ashley",

greet: function (customer) {

customer = customer || " there!";

return "Hi" + customer + " My name is " + waitress.name + "; what can I get you?"; </script>

}

};

doppelganger = waitress;

waitress = null;

doppelganger.greet(); // failure!

Think about this code: remember that objects are a reference value. This means that when we create an object literal, it is stored in memory in only one place. When we set doppelganger = waitress, both variables point to the same object in memory. At this point, doppelganger.greet()would work fine. However when we remove waitress's "pointer" to the object in memory, things break. What we need is some way to refer to the object itself without using any of the variables that point to it.

Now you see why we use this.name. Inside an object literal, this points to that object itself.

Example 4.8

var waitress = {

name : "Ashley",

greet: function (customer) {

customer = customer || " there!";

return "Hi " + customer + " My name is " + this.name + "; what can I get you?";

}

};

alert( waitress.greet("Joe") ); // Hi Joe My name is Ashley; what can I get you?

Object Oriented JavaScript

In the previous chapter, we talked for a very short while about objects. Now, our discussion of this has led us back down the trail of objects in JavaScript, and—since everything in JavaScript is an object—I think we should continue.

I should note that we're only going to touch the tip of the tip of the tip of how you can manipulate objects in JavaScript. I have screencast series on Object-Oriented Programming in JavaScript on the Tuts+ Marketplace, and if you'd like to delve into a more advanced view of OOP (in JavaScript, of course), you might want to check that out.

You know that constructor functions coupled with the keyword new are a decent way of making objects. To recap that, make sure you're grokking this:

function Computer (name, ram_amount, memory_amount) {

this.name = name;

this.RAM = ram_amount; // in GBs

this.space = memory_amount; // in MBs

}

This is a normal function that will create an object if we call new Computer("MacBook", 2, 250000 ). Note that this isn't the prototype (or blueprint) of all computer objects; it's the constructor of them.

What about adding a function to this computer object, such as the ability to store a file? You might be tempted to do something like this:

function Computer (name, ram_amount, memory_amount) {

this.name = name;

this.RAM = ram_amount;

this.space = memory_amount;

this.files = [];

this.store_file = function (filename, filesize) {

this.files.push(filename);

this.space -= filesize;

};

}

That seems innocuous enough; however, there is a problem here. You shouldn't create functions inside your constructor functions because every time you create a new copy of that object, you'll be creating a new copy of that function in memory. There's no need for this, because we can have just one copy of the function that works for all Computer objects. This works because we use this to refer to the object inside the function.

So what we need is a way to point every copy of the Computer to a store_file function. It's nice the way we've got it now, because the function is a method, so this refers to the given object. We can do this—and only need one function—with the prototype of Computer. Here's how that's done:

Computer.prototype.store_file = function (filename, filesize) {

this.files.push(filename);

this.space -= filesize;

};

Remember that functions are objects too, so they can have properties. In this case, we're accessing the prototype property, which is an object that all Computer objects inherit from. What that means is this: when you run my_computer.store_file("image.jpg", 26), the JavaScript engine sees that my_computer doesn't have a method called store_file, so it looks on my_computer's prototype object, which is Computer.prototype. It will find it there, and execute it as a method of my_computer. If it didn't find it there, it would continue up the prototype chain. In this case, the next step up is Object.prototype, which is the top of everything in JavaScript.

I want to make sure you're understanding what is really going on here. There are two main parts to creating an object with a constructor function and the keyword new:

1. The constructor function creates an object (denoted by this inside the function); within the function, we are assigning the values of properties of the object.

2. The prototype, or parent object, of every object made with a given constructor function is stored at ConstructorFunction.prototype. All the methods and properties of this object are accessible from the "children" objects.

This is why it's called "Prototypal Inheritance"; each object inherits from the same prototype. It's important to note that if a given child object has a given property of it's own—say, my_obj.name—the prototype won't be checked for the property. Also, note that when you change a property or method from an object, you're changing the property on that object, not the prototype object.

Let's look at an example, just to cement this down:

Example 4.9

function Product(name) {

if (name) {

this.name = name;

}

}

Product.prototype.name = "To be announced";

Product.prototype.rating = 3;

var ipad = new Product("iPad");

alert( ipad.name ); // "iPad";

alert( ipad.rating ); // 3

Here, we've created a simple Product. Right now, you can see that the name property is right on the object ipad and the rating property is being inherited from its prototype.

Example 4.10

// ipad from above

ipad.rating = 4;

ipad.rating; // 4

Product.prototype.rating; // 3

By changing the rating, we're actually adding a rating parameter to the ipad object. Since it has its own property called rating now, when we ask for ipad.rating, it no longer goes to the prototype … however, the prototype's value for rating hasn't been changed.

Object Methods

We discussed methods for every type except Objects at the end of the last chapter. This was for two reasons:

· I wanted to keep all object-related material together, right here.

· Most of the methods you'll use on objects will be ones you create yourself.

However, there are several useful methods that are built into objects. Since every object you create is an Object (i.e, inherits from Object.prototype), these methods are stored there.

ROCKSTAR TIP

This revelation might get you wondering where the methods for, say, strings, are stored. Well, there is a String object, which has a prototype property. That's where they are kept. Some string methods are also object methods; since everything is an object—meaning that Stringinherits from Object.prototype, too—String doesn't need to have its own versions of those methods, except when they are different from the Object versions.

hasOwnProperty

We talked about using a for-in loop to iterate over arrays in the last chapter; you can use this on objects, too.

Example 4.11

function Person(name) {

this.name = name;

}

Person.prototype.legs = 2;

var person = new Person("Joe"), prop;

for (prop in person) {

console.log(prop + ": " + person[prop]);

}

// in console:

// name : Joe

// legs: 2

However, there's something to be aware of here. If your object is inheriting from a prototype with properties, those properties will be looped over as well. This might make for-in cough up results you didn't want. In this case, objects have a handy method for determining if a given property belongs to the object or its prototype: it's called hasOwnProperty:

Example 4.12

function Person(name) {

this.name = name;

}

Person.prototype.legs = 2;

var person = new Person("Joe"), prop;

for (prop in person) {

if (person.hasOwnProperty(prop)) {

console.log(prop + ": " + person[prop]);

}

}

// console:

// name: Joe

It's a bit inefficient to have to write that inner if block every time you want to loop over an object, but get used to it; it's a best practice.

toString

Every object has a toString method. This method is called when the object is to be printed out anywhere; it converts it to a string. The different built-in types do different things: strings obviously don't change; numbers become strings of numbers; dates become nicely formated date strings. But what about general objects?

Example 4.13

var o = { name : "Andrew" };

alert( o.toString()); // "[object Object]"

This is pretty useless, because it tells you absolutely nothing about the object, other than that it is indeed an object. Use this as a reminder to create a custom toString method if you'll need it. You could do this:

Example 4.14

var person = {

name : "Joe",

age : 30,

occupation: "Web Developer",

toString : function () {

return this.name + " | " + this.occupation;

}

};

alert( person.toString() ); // "Joe | Web Developer"

Usually, you won't be calling the toString method yourself; the JavaScript engine will call it for you when you try to use the object (built-in type or not) where you would use a string.

valueOf

This method returns a primitive value that would represent your object. For example:

Example 4.15

var account = {

holder : "Andrew",

balance : 100,

valueOf : function () {

return this.balance;

}

};

alert( account + 10 ); // 110

As you can see, when we try to add 10 to account, we get 110, even though account is an object. Obviously, we can't assign to objects like this, but it works for this kind of thing. This method is like toString, in that you don't usually call it yourself.

You might be wondering when the JavaScript engine decides to use toString and when to use valueOf. That's a bit complicated for this beginner's book; this StackOverflow thread might be of help.

That's it; as you can see there really isn't much in the way of object methods.

Closure

Closure is one of the most important features of JavaScript. If you're familiar with other programming languages (specifically object-oriented ones), you might know about private variables. A private variable is a variable that is accessible to the methods of an object, but isn't accessible from outside the object. JavaScript doesn't have this, but we can use closure to "make" private variables. This is just one way of putting closure to work for you. But enough about why it's useful; let's see how to implement it!

Before we begin, remember two important points about JavaScript that contribute to closure:

· Everything is an object, even functions. This means we can return a function from a function.

· Anonymous, self-invoking functions are nameless functions that run immediately and usually only run once.

Now, let's use these two ideas to create a closure. First, let's look at some "normal" JavaScript code:

var secretNumber = 1024;

function revealSecret(password) {

if (password === "please") {

return secretNumber++;

}

return 0;

}

This should be old hat to you now. We have a variable called secret_number and a function that returns that number if the password is correct. The post-increment operator adds one to secret_number after we have used it (in this case, that means after we have returned it); this way, we get a unique number each time we call the function. If the password is wrong, we get 0.

However, there's an obvious problem there: there's nothing secret at all about secret_number; it's a global variable that everyone has access to. To fix that, why don't we just put it inside the function? Then, we won't be able to view or change it from outside the function.

Hold on, though; we can't do that either. If we do, each time we call the function, it will reset secret_number to 1024. What to do? Closure to the rescue! Examine the following:

Example 4.16

var revealSecret = (function () {

var secretNumber = 1024;

return function (password) {

if (password === "please") {

return secretNumber++;

}

return 0;

};

}());

alert( revealSecret("please") ); // 1024

alert( revealSecret("please") ); // 1025

Notice that revealSecret is being assigned to the return value of the anonymous self-invoking function. Since that function runs right away, revealSecret will be whatever is returned. In this case, that's a function. Now, here's the impressive part. Notice that the internal function (the one being returned) references the secretNumber variable from its "parent" function's scope. Even after the anonymous function has returned, the inner function will still have access to this variable. That's closure: an inner function having access to the scope of it's parent function, even after the parent function has returned. This way, secretNumber is set only once, it can safely be incremented each time it's used, and no one can get to it, because it's protected by the scope of the anonymous function. Putting it another way, closure is the concept of exposing limited control of a function's scope outside the function.

Another place where this is useful is in creating modules. Check this out:

var a_module = (function () {

var private_variable = "some value";

function private_function () {

// some code;

}

return {

public_property : "something"

// etc : " ... "

};

}());

This is the module pattern: inside a anonymous self-invoking function, we create variable and methods that we don't have available from the outside. Then, we return an object with public properties and methods that use these private variable and methods. This way, the "guts" that shouldn't be exposed aren't. If you want to read more about the module pattern, check out this post of the YUI Blog.

You probably understand the "how" of closure. Maybe you're still struggling with the "why." After all, it's your code and you know enough not to hurt anything, or change something that shouldn't be changed. Well, building in protection like this is one of the best practices of good coding. It's defensive; coding this way means you're aware of the things that can go wrong and are actively preventing them. Also, there's a good chance your code will eventually be used by others; they won't know necessarily how things are "supposed" to work, and coding this way will prevent rampant breakage in such situations.

For example, look back up at the revealSecret function about. We might know not to change the secretNumber variable, but another developer might not … or we might forget. Basically, any situation where you want to be able to change a value over multiple executions of a function (meaning you can't put the value inside the function), but not have that value changeable from outside the function (meaning you can't put the value outside the function) is a situation where closure comes to your rescue.

It's not just other programmers that you have to prepare for. Nine times out of ten, your programs will interact with data from the user. But who is to say that the user will docilely do as they are told and input the right type of information. Defensive coding sometimes means having a backup plan for situations like these.

Errors

This brings us to errors in your JavaScript. Now, there are really two types of errors: errors you make while coding—things like syntax errors and typos—and errors that are unforeseeable—things are break because of something outside your code, such as the user's input, or a missing feature in the JavaScript engine. While the JavaScript engines usually silently solves small errors (such as a missing semicolon), a larger mistake will make it throw (yes, that's the technical term—throw) an error. Also, we can throw our own errors, if something goes wrong.

Here's the error-protection syntax:

try {

// code that might cause an error here

} catch (e) {

// deal with the error here

}

We wrap the code that might throw an error in a try block. If we don't do this, the JavaScript engine will deal with the error itself, which usually means stopping the execution of your code and potentially showing the user the error: not good. If an error is thrown, the error object (which we'll look at soon) is passed to the catch block (you can call it whatever you want; in this case, I'm calling it e, which is common). Inside the catch block, you can deal with the error.

Different web browsers include different properties on the error object. They all include the error name and the error message. Firefox also includes the file name and line number of the error. Chrome includes a stack trace. There are other things, but the main ones are name and message, which are the type of error and a description of what happened, respectively. You can throw your own errors using the throw keyword and creating an error object. You can create this error object as an object literal, or you can use the error constructor functions.

What kinds of things will the JavaScript engine throw an error on? Try calling a function that doesn't exist, or accessing a property of null; yep, you'll get an error. However, it's useful to be able to throw our own errors, so let's see how it's done:

Example 4.17

function make_coffee(requested_size) {

var sizes = ["large", "medium", "small"],

coffee;

if (sizes.indexOf(requested_size) < 0) {

throw new Error("We don't offer that size");

}

coffee = { size: required_size, added: ["sugar", "sugar", "cream" ] };

return coffee;

}

try {

make_coffee("extra large");

} catch (e) {

console.log(e.message);

}

You might find this to be a common pattern. When there's the possibility of an error, you'll throw it within a function. Then, you'll wrap the calling of that function in a try statement and catch the error, if there is one. The way it works is that as soon as the error is thrown, the program jumps to the catch statement, so nothing after the error is ever executed. As you can see, we're using the Error constructor function, passing in our error message.

Testing your JavaScript

Let's talk about testing your code. Testing is like pictures of kittens: it's impossible to have too much of it. You should constantly be testing your code. There are two main types of testing: performance testing and unit testing.

· Unit testing refers to testing each bit of functionality (each unit) in your code. You may even want to use the practice "Test Driven Development," which means you write your tests first, so you know what the code you are about to write is supposed to do.

· Performance testing refers to making sure you have written your code in the fastest way possible. No, I'm not referring to the length of time it took you to code. I mean the length of time is takes your code to run. It's important to have efficient code.

Let's look at each of these types of testing individually.

Unit Testing

So, testing each unit of your code: it sounds like a good idea, but how do you do it? Well, here's the basic process:

· Write your tests

· Run your tests and watch them fail

· Write your code

· Run your tests and watch them pass

· Refactor (clean up) your code

· Rinse and repeat for each feature

This is the process for test-driven development: by writing the tests first, you'll have a goal to work towards. Don't feel bad about failing tests; at first, you want them to fail. If they don't fail, you've probably misunderstood your goals or written poor tests.

So how do you write these tests? Often, you'll use a testing framework (we'll talk about frameworks and libraries in the next chapter). However, it's not too hard to write your own testing functionality.

Before we write our tests or test functionality, let's ask this: what types of things should we be testing for? Here are the two types of tests common testing frameworks implement:

· assert: determines is something is true or not

· equal: determines if two things are equal

We could write these functions ourselves … so let's do that now! Note: this will assume that you're testing your JavaScript in a web browser, because this is the case more often than not. This means we're going to deal with the Document Object Model, which you might not know about yet. Don't worry, we cover all the ugly aspects of the DOM in the next chapter. You can jump there if you'd like, or hang on for the ride. It won't be much right now, so you shouldn't have to worry.

Example test.js

var TEST = (function () {

var results = document.createElement("ul");

results.id = "tests";

document.body.appendChild(results);

function log(class_name, msg) {

var li = document.createElement("li");

li.className = class_name;

li.appendChild(document.createTextNode(msg));

results.appendChild(li);

}

return {

assert : function (bool, msg) {

log((bool) ? "pass" : "fail", msg);

},

equal : function (first, second, msg) {

log((first === second) ? "pass" : "fail", msg)

}

};

}());

Notice I'm using the module pattern to create our little testing framework. It creates an unordered list and sticks it on our page. Then, for each test we execute, we stick a new list item in the list. If the test passes, we give the list item a class of "pass"; if it fails, we give it a class of "fail." This way, we can style the list through CSS.

Our framework has two methods The assert method takes two parameters. The first parameter is the value we're testing. If its Boolean value is true, the test passes. Using the conditional operator makes this extremely easy, because the only difference between a passing test and a failing test is the class on the list item. The second parameter is the message that identifies the test.

The second method, equal, takes three parameters. If the first two are equal, the test passes. If they aren't, it fails.

Let's step away from testing for a moment to make sure you understand the code above. Since both test functions are pretty similar, I've taken that similar functionality and put it in a private method called log; it's private because we're using the module pattern, and we have access to it via closure. Inside each testing method, we just call log and pass it the class name to give the element and the message to put in the list item. As I mentioned, I'm using the conditional operator to decide whether the test passes or fails right inside the call to the function. Inside the log function, we create the list item, give it the appropriate class and test, and append it to the unordered list we created.

So, let's use the framework now. Obviously, we're not going to build an entire project right here, but let's say we're going to build a Business object. We start by writing the most simple test possible, to test for its existence.

ROCKSTAR TIP

I haven't included the CSS that goes along with this little test framework here; if you want to see that, and follow along with these tests, check out the example files for these examples in the downloadable source code.

Example 4.18

TEST.assert(Business, "Existence of Business function");

If you run this now, the test will fail; actually, you won't even get a test, because your browser will throw an error saying there's no such thing as Business. That's ok; our test obviously failed. Now, let's write the function:

Example 4.19

function Business (name, year_founded) {

}

TEST.assert(Business, "Existence of Business function");

Now we have our function; re-run the test and it should pass! Now, let's add some other tests:

var b = new Business("my business", 2000);

TEST.equal(b.name, "my business", "b.name === 'my business'");

TEST.equal(b.year_of_founding, 2000, "b.year_of_founding === 2000");

They fail, of course, so let's fix that:

Example 4.20

function Business (name, year_founded) {

this.name = name;

this.year_of_founding = year_founded;

}

var b = new Business("my business", 2000);

TEST.equal(b.name, "my business", "b.name === 'my business'");

TEST.equal(b.year_of_founding, 2000, "b.year_of_founding === 2000");

Now, they should pass. One more:

TEST.assert(b.get_age, "b has get_age");

TEST.equal(typeof b.get_age, "function", "b.get_age is a function");

After making sure it fails, you can add the function:

Example 4.21

function Business (name, year_founded) {

this.name = name;

this.year_of_founding = year_founded;

}

Business.prototype.get_age = function () {

return (new Date().getFullYear()) - this.year_of_founding;

}

var b = new Business("my business", 2000);

TEST.assert(b.get_age, "b has get_age");

TEST.equal(typeof b.get_age, "function", "b.get_age is a function");

Now, it should pass.

This is just a very basic example of how you might do testing. There are whole books written about this kind of thing, so I can't really do the topic justice. If you want to learn more, check out "Test-Driven JavaScript Development" by Christian Johansen. You can read an excerpt of the bookover on Nettuts+.

Performance Testing

Often, there are several ways to do something with JavaScript. This doesn't mean all ways are equal, however. Very often, one way is faster than another. This is where performance testing comes in. In this type of testing, you test two (or more) different ways of doing something and compare their speeds.

If you want to test something small, there's an informal way of doing this.

· Store the current time

· Run your test

· Store the new current time

· Subtract the two times to see how long it took

If your code will be running in different browsers, you'll want to run your tests in all those environments. Sometimes—often due to the way the JavaScript engine is implemented—what's fastest in one browser won't be what's fastest in another.

Let's see how to implement one of these tests. But what to test? We'll use an test I did a while ago. Here's the scenario I had: I had two arrays, and I wanted to add all the items from the second array to the first array. There are three ways to do this:

1. Loop over the second array and push each item into the first array one by one.

2. Use array's concat method; this returns a new array with the items in both arrays, but we can just reassign the variable that has the first array

3. Use the fact that array's push method can take as many parameters as we want to give it and use the function's apply method to turn that second array into a list of parameters.

So, let's see how we would test this; I'll go over this piece by piece:

Example 4.22 a

var d1, d2, d3, d4, d5, d6,

arr1 = [1,2], arr2 = [],

i = 0, len;

for ( ; i < 100000; i++) {

arr2[i] = i;

}

i = 0;

len = arr2.length;

This sets up our testing environment. We've got a bunch of variables to keep our times. We have the first array and the second array. We're putting 100,000 items in the second array because modern JavaScript engines are so fast that we need to make a big test, or else everything will happen in zero milliseconds. Now, let's run the first test:

Example 4.22 b

d1 = new Date().getTime();

for ( ; i < len; i++) {

arr1.push(arr2[i]);

}

d2 = new Date().getTime();

Here it is; we capture the current time, run the test, and capture the new current time. As you may recall, the getTime method of Date objects return the number of millisecond since January 1, 1970. If we subtract d1 from d2, we'll get the number of milliseconds it took to run the test (see a few paragraphs down).

Next test!

Example 4.22 c

arr1 = [1,2];

d3 = new Date().getTime();

arr1 = arr1.concat(arr2);

d4 = new Date().getTime();

We have to start by resetting arr1, because it was changed in the previous test. We've captured our times, so let's do the last test now:

Example 4.22 d

arr1 = [1,2];

d5 = new Date().getTime();

Array.prototype.push.apply(arr1, arr2);

d6 = new Date().getTime();

This might seem a bit cryptic. Basically, we're using the fact that the apply method of functions takes an array of arguments as it's second parameters. Since we can't just do arr1.push(arr2) (that would make arr2 an item in arr1, instead of each of arr2's items), we're doing it this way.

At the end, we can do this:

Example 4.22 e

console.log("looping and pushing: ", (d2 - d1) );

console.log("array's concat: ", (d4 - d3) );

console.log("push via apply: ", (d6 - d5) );

The test with the lowest score (the quickest running time) is the fastest. Remember that time might change between browsers, so be sure to check all the browsers your code might be running in. To make this easier, I like to use the web app JSBin; it's made to easily share quick snippets of code. Just paste your tests in the left panel (the JavaScript panel), and hit "Preview." You can also click "Save," and then copy the URL. This is a unique URL that you can use to test that snippet in any browsers. If you want to try this test in JSBin, you can get it at this URL:http://jsbin.com/ejogo5

A note here: When using JSBin, you'll probably want to change the console.log lines to something like this:

document.write("<br />looping and pushing: " + (d2 - d1) );

document.write("<br />array's concat: " + (d4 - d3) );

document.write("<br />push via apply: " + (d6 - d5) );

Fig. 4-1. JSBin

You'll want to run the test a couple times to see which one is really fastest. In my case, running this test in FireFox 3.6.10 shows that "push via apply" is the fastest. However, your mileage will definitely vary.

This is a pretty rough and dirty way of testing; it's primary appeal is that it's quick and easy. It's really not very scientific. If you want to do some real performance testing, you'll want to check out JSPerf. This site will comprehensively test your code, as well as keep track of the score in all the browsers you test in. Let's see how it works:

Here's what you'll see on the home page:

Fig. 4-2. JSPerf

It's pretty simple: just go down the form and put in your code. There's a place to put in any starting HTML or JavaScript code that's needed for the test, but isn't part of the code you want to test. Then, you add a title for each test code snippet and fill in the code. You can have as many test snippets as you want. When you're done, hit "Save Test Case." You'll be taken to the test case page, where you can run the test. Hit run test, and wait. It will run the test, tell you which code snippet was fastest, and by how much. Then, it stores the results from your browser in a table below, so you can compare different browsers. Just copy that URL and try the test in a different browser, to see how it performs. Note that JSPerf shows the results as "Operations Per Second"; therefore, a higher number is better.

JSPerf tests are publicly visible, so you can see what tests other people have run.

Organizing your JavaScript

There's more to programming that rapidly smashing your fingers against the keyboard. There's the meta part, like the number of files you put your JavaScript code in, or how to organize the code within those files. These are things beginners often don't think about, so let's take a look at them.

One File, or Many?

Let's start with files. As you know from Chapter 1, JavaScript code is stored in a file with the extension "js"; you also know that there are two ways to include JavaScript in your web page:

<script src="path/to/script.js"></script>

<script>

// include that code inline

</script>

Because it's wise to separate your content and functionality, the first method above is better practice. But should all your JavaScript go in one file? Or should you separate it into different files?

When you're coding, it's definitely easier to break that code into several files. Since JavaScript global variables (the ones outside functions) are available from a global object accessible everywhere that JavaScript is on the page, you can create variables in one file and access them another, as long as both files are linked to in your HTML.

However, splitting your JavaScript into several files comes with a cost: that cost is paid by your website visitors. Here's why: for every file their browser needs to download, it is downloading more than just the code. There's the overhead—like HTTP headers—that comes with the file. Because of this, it's much better to store all your code in one file, to minimize the amount of overhead.

The best medium here would be to develop your code in separate files and then concatenate those files together when you're ready to publish the site. There are programs (such as build scripts) that can help you automate this process. This might be a bit beyond your skill level at this point, but if you're ready for it check out my tutorial on using Ant to compile and compress JavaScript, published on Nettuts+ (See the section below for more on compression).

Global Variables

By now you're familiar with the concept of global variables. You might think this is a great think, since everything is always accessible. However, that's not the case. Here's why: the more you write JavaScript, the more you'll find that the code you use on a given page isn't just yours: you'll use libraries, helper methods, and other code from other developers. If your site has advertising, you'll find that many advertisers insert their ads via JavaScript. If all the code relies on global variables, there's a really good chance that one script will overwrite the variables of another script. Since there's no protection against this built into JavaScript engines, you have to code very defensively. Because of this, it's a best practice to use as few global variables as possible.

How can you do this? Well—and I hate to sound like a broken record, but—here's another place that anonymous, self-invoking functions are really useful. If all your code can be contained in one place, you can do this:

(function () {

// all your code goes here

}());

This way, you don't have to worry about anyone getting at your variables; they are all safely tucked away inside the scope of the anonymous function. And since functions can access the variables in the scope outside them, you can access any global variables that other libraries set.

But what if you're writing a library, or some similar code that needs to be accessed outside of itself? In cases like this, you'll have to use a global variable. That's not a bad thing, as long as you name and set it properly. You'll probably want to use the module pattern for this if you want to have your private variables and methods. Then, assign a returned object or function (depending on the complexity of your library) to the global variable.

I prefer to give my global variables all uppercase names; I do this for two reasons:

1. It makes it clear to me when I'm reading my code that it's a global variables.

2. It reduces the chance of having that variable overwritten, because most libraries don't do this (yet!).

You might want to adopt this principle.

The Good Parts and JSLint

Here's a dirty secret I've been hiding all along the way: JavaScript has bad parts. There are several terrible features in JavaScript that you should never ever use. I haven't mentioned any of these anywhere at all in this book, so you currently have a relatively "pure" understanding of JavaScript.

ROCKSTAR TIP

Don't misunderstand me here: this doesn't mean that if you hear about something not mentioned in this book, it's a bad part; I just couldn't fit it in! Check out the appendices for more great resources and topics you should look into next.

However, you should really know about the bad parts, eventually. I really recommend you get Douglas Crockford's book JavaScript: The Good Parts. It will do more than just teach you what's naughty and what's nice about JavaScript. You'll really be taken to a new level of JavaScript understanding.

Once you've read the book (or even before!), you can run your JavaScript through JSLint, Douglas Crockford's JavaScript code quality tool. At the top, paste in your code. Then, at the bottom, choose the best practices you want JSLint to check for. If it finds places where you aren't using those best practices, it will let you know.

Fig. 4-3. JSLint

Remember, your code will probably still run, even if it doesn't pass the JSLint test. This is just a self-check. Also, realize that there are several very reputable JavaScript developers who don't see eye to eye on everything Crockford calls a Bad Part. Ultimately, you'll have to weigh both sides and decide what's right for yourself.

Optimizing your JavaScript

We talked a bit about how one JavaScript file is better for your site visitors than multiple ones. There's something else you can do to improve the time it takes your site to load for a visitor: JavaScript minification. The idea here is that every byte counts when a site visitor is downloading the JavaScript file. To improve that time, we can take out all the whitespace (spaces, tabs, line breaks, etc.) and shorten all the variables names, since these extra bytes are really just there to make our jobs easier, and aren't necessary for the code to run properly.

So, when you're website is finished, you can go through your code and take out all the whitespace.

Actually, that's not necessary. There are command-line tools that do this for you. Since this is only a significant benefit if you have a lot of JavaScript, I'll leave it to you to explore this topic more. You can check out JSMin, YUI Compressor, or Google Closure. But first, I'd really recommend reading Nicolas Zakas' articles Better JavaScript Minification and JavaScript Minification Part II. Really, this whole idea of making your JavaScript faster is quite a large topic, so if you're really interested, check out Zakas' book High Performance JavaScript.

Summary

We've covered a lot in this chapter. We've looked at Object-Oriented Programming with JavaScript prototypes. We've delved into the concepts of closure and error checking. Then, we discussed the important topics of good coding practices, including testing, organizing, and optimizing your code.

But we've still got a few topics to cover. Next up, we're going to talk about the specifics of working with HTML elements in the browser. It will be slightly intimidating, but you'll by grokking it in no time!