Chapter 4. JavaScript Functions and Objects: Serious JavaScript

image with no caption

Can you call yourself a scripter yet? Probably—you already know your way around a lot of JavaScript. But who wants to be a scripter when you can be a programmer? It’s time to get serious and take it up a notch—it’s time you learn about functions and objects. They’re the key to writing code that is more powerful, better organized and more maintainable. They’re also heavily used across HTML5 JavaScript APIs, so the better you understand them the faster you can jump into a new API and start ruling with it. Strap in, this chapter is going to require your undivided attention...

Expanding your vocabulary

You can already do a lot with JavaScript, let’s take a look at some of the things you know how to do:

image with no caption
image with no caption

So far, though, a lot of your knowledge is informal—sure, you can get an element out of the DOM and assign some new HTML to it, but if we asked you to explain exactly what document.getElementById is technically, well, that might be a little more challenging. No worries; by the time you leave this chapter you’re going to have it down.

Now to get you there, we’re not going to start with a deep, technical analysis of getElementById, no no, we’re going to do something a little more interesting: We’re going to extend JavaScript’s vocabulary and make it do some new things.

How to add your own functions

You’ve been using built-in functions, like alert, or even Math.random, but what if you wanted to add your own? Let’s say we wanted to write some code like this:

Create a checkGuess function

image with no caption

How a function works

So how does this all work? What happens when we actually invoke a function? Here’s the 10,000-foot view:

Okay, first we need a function.

Let’s say you’ve just written your new bark function, which has two parameters, dogName and dogWeight, and also a very impressive bit of code that returns a dog’s bark, depending on its weight of course.

image with no caption

Now let’s invoke it!

You know how to call a function already: just use its name and give it any arguments it needs. In this case we need two: a string with the dog’s name, and the dog’s weight, which is an integer.

Let’s make that call and see how this works:

image with no caption

And, let the body of the function do its work.

After we’ve assigned the value of each argument to its corresponding parameter in the function—like “Fido” to dogName and the integer 50 to dogWeight—then we’re ready to evaluate all the statements in the function body.

Statements are evaluated from top to bottom, just like all the other code you’ve been writing. What’s different is that we’re doing it in an environment where the parameter names dogName and dogWeight are assigned to the arguments you passed into the function.

image with no caption

Optionally, we can have return statements in the body...

... and that’s where we return a value back to the code that makes the call. Let’s see how that works:

Note

Remember, functions aren’t required to return a value. But in this case, the bark function does return a value.

image with no caption
image with no caption

If we could have another moment to talk...

We know, we know, by Chapter 4 you thought you’d be flying in an HTML5 jetpack by now, and we’ll get there. But before we do, you really need to understand the underpinnings of the HTML5 JavaScript APIs, and we’re going to do that in this chapter.

So what are these underpinnings? Think of the HTML5 JavaScript APIs as made up of objects, methods (otherwise known as functions) and properties. And so to really get in and master these APIs, you need to understand those things pretty well. Sure, you could try to get by without knowing them, but you’ll always be guessing your way around the APIs while failing to use them fully (not to mention making lots of mistakes and writing buggy code).

So we just wanted to drop you a note before you got too far into this chapter to tell you what we are up to. Here’s the great thing: by the end of this chapter you’re going to understand objects, functions, methods and a lot of other related things better than about 98% of JavaScript scripters out there. Seriously.

image with no caption

No, they’re different.

When you define a function you can define it with one or more parameters.

image with no caption

When you call a function, you call it with arguments:

image with no caption

So you’ll only define your parameters once, but you’ll probably call your functions with a lot of different arguments.

Note

You’d be amazed how many people get this wrong—even books get it wrong, so if you read it differently elsewhere, now you know better....

You define a function with parameters, you call a function with arguments.

Local and Global Variables

Know the difference or risk humiliation

You already know that you can declare a variable by using the var keyword and a name anywhere in your script:

image with no caption
image with no caption

And you’ve seen that you can also declare variables inside a function:

image with no caption

If a variable is declared outside a function, it’s GLOBAL. If it’s declared inside a function, it’s LOCAL.

But what does it matter? Variables are variables, right? Well, where you declare your variables determines how visible they are to other parts of your code, and, later, understanding how these two kinds of variables operate will help you write more maintainable code (not to mention, help you understand the code of others).

Knowing the scope of your local and global variables

Where you define your variables determines their scope; that is, where they are defined and where they aren’t, where they’re visible to your code and where they aren’t. Let’s look at an example of both locally and globally scoped variables—remember, the variables you define outside a function are globally scoped, and the function variables are locally scoped:

image with no caption

The short lives of variables

image with no caption

When you’re a variable, you work hard and life can be short. That is, unless you’re a global variable, but even with globals, life has its limits. But what determines the life of a variable? Think about it like this:

Globals live as long as the page. A global variable begins life when its JavaScript is loaded into the page. But, your global variable’s life ends when the page goes away. Even if you reload the same page, all your global variables are destroyed and then recreated in the newly loaded page.

Local variables typically disappear when your function ends. Local variables are created when your function is first called and live until the function returns (with a value or not). That said, you can take the values of your local variables and return them from the function before the variables meet their digital maker.

Note

We say “typically” because there are some advanced ways to retain locals a little longer, but we’re not going to worry about them now.

So, there really is NO escape from the page is there? If you’re a local variable, your life comes and goes quickly, and if you’re lucky enough to be a global, you’re good as long as that browser doesn’t reload the page.

But there just has to be a way to escape the page! We can find a way! Can’t we?

Note

Join us in the Web Storage chapter where we’ll help our data escape the dreaded page refresh!

image with no caption

You “shadow” your global.

Here’s what that means: say you have a global variable beanCounter and you then declare a function, like this:

image with no caption

When you do this, any references to beanCounter within the function refer to the local variable and not the global. So we say the global variable is in the shadow of the local variable (in other words we can’t see it because the local version is in our way).

Note

Note that the local and global variables have no effect on each other: if you change one, it has no effect on the other. They are independent variables.

Oh, did we mention functions are also values?

OK, you’ve used variables to store numbers, boolean values, strings, arrays, all kinds of things, but did we mention you can also assign a function to a variable? Check this out:

image with no caption

Well, not only did we fail to mention this little detail about functions before now, but we also weren’t totally honest when we told you about the anatomy of a function—as it turns out, you don’t even have to give your function a name. That’s right: your function can be anonymous. What the heck does that mean, and why would you want to do such a thing? First let’s see how you create a function without a name:

image with no caption

Brain Power

Take a look at this code: what do you think is going on?

This should start to look a little more understandable with what we just covered...

image with no caption

What you can do with functions as values

So what’s the big deal? Why is this useful? Well, the important thing isn’t so much that we can assign a function to a variable, that’s just our way of showing you that a function actually is a value. And you know you can store values in variables or arrays, you can pass them as arguments to functions, or as we’ll soon see, you can assign them to the properties of objects. But, rather than talking you through how anonymous functions are useful, let’s just look at one of the many ways using functions as values starts to get interesting:

image with no caption

Or we could get even fancier:

image with no caption

You might be starting to see that functions can do some useful things beyond just packaging up code for reuse; to give you a better idea of how to fully take advantage of functions, we’re going to take a look at objects and see how they fit into JavaScript, and then we’ll put it all together.

image with no caption

Well we thought we’d covered that already... but if it looks like we’ve picked you up and have driven you halfway around the city with the meter running (when we could have driven you straight downtown), well, then remember we’re about to start diving into the APIs that work with HTML5 in the next chapter. And, doing that is going to require that you really understand functions, objects and a few other related topics.

So hang in there—in fact you’re halfway there! And don’t forget, this is the chapter where you’re going from scripter to programmer, from an HTML/CSS jockey to someone who is capable of building real apps.

Note

Did we already mention that is probably going to make you a lot more money too?

image with no caption

Did someone say “Objects”?!

Ah, our favorite topic! Objects are going to take your JavaScript programming skills to the next level—they’re the key to managing complex code, to understanding the DOM, to organizing your data, and they’re even the fundamental way HTML5 JavaScript APIs are packaged up (and that’s just our short list!). That said, objects are a difficult topic, right? Hah! We’re going to just jump in head first and you’ll be using them in no time.

Here’s the secret to JavaScript objects: they’re just a collection of properties. Let’s take an example, say, a dog. A dog’s got properties:

image with no caption

Thinking about properties...

Of course Fido would be the first to admit there’s a lot more to him than just a few properties, but for this example, those are going to be the ones we need to capture in software. Let’s think about those properties in terms of JavaScript data types:

image with no caption

How to create an object in JavaScript

So we’ve got an object with some properties; how do we create this using JavaScript? Here’s how:

image with no caption

Some things you can do with objects

  1. Access object properties with “dot” notation:

    image with no caption
  2. Access properties using a string with [] notation:

    image with no caption
  3. Change a property’s value:

    image with no caption
  4. Enumerate all an object’s properties:

    image with no caption
  5. Have fun with an object’s array:

    image with no caption
  6. Pass an object to a function:

    image with no caption
    image with no caption

Note

The Dot Operator.

The dot operator (.) gives you access to an object’s properties. In general it’s easier to read than the [“string”] notation:

  • fido.weight is the size of fido.

  • fido.breed is the breed of fido.

  • fido.name is the name of fido.

  • fido.loves is an array containing fido’s interests.

image with no caption

Yes, you can add or delete properties at any time.

To add a property to an object you simply assign a new property a value, like this:

fido.age = 5;

and from that point on fido will have a new property: age.

Likewise, you can delete any property with the delete keyword, like this:

delete fido.age;

When you delete a property, you’re not just deleting the value of the property, you’re deleting the property itself. In fact, if you use fido.age after deleting it, it will evaluate to undefined.

The delete expression returns true if the property was deleted successfully (or if you delete a property that doesn’t exist or if what you’re trying to delete isn’t a property of an object).

Let’s talk about passing objects to functions

We’ve already talked a bit about how arguments are passed to functions—arguments are passed by value, so if we pass an integer, the corresponding function parameter gets a copy of the value of that integer for its use in the function. The same rules hold true for objects, however we’ve got to look a little more closely at what a variable holds when it is assigned to an object to know what this means.

When an object is assigned to a variable, that variable holds a reference to the object, not the object itself. Think of a reference as a pointer to the object.

image with no caption

So, when you call a function and pass it an object, you’re passing the object reference—not the object itself, just a “pointer” to it. A copy of the reference is passed into the parameter, which then points to the original object.

So, what does this all mean? Well, when you change a property of the object, you’re changing the property in the original object, not a copy, and so, you’ll see all the changes you make to an object within and outside of your function. Let’s step through an example using a loseWeight function for dogs...

Putting Fido on a diet....

Let’s take a look at what’s going on when we pass fido to loseWeight and change the dog.weight property.

Behind the Scenes

image with no caption
  1. We’ve defined an object, fido, and we are passing that object into a function, loseWeight.

    image with no caption
  2. The dog parameter of the loseWeight function gets a copy of the reference to fido. And so, any changes to the properties of the parameter affect the object that was passed in.

Our next showing is at....

We’ve already had a small taste of mixing objects and functions. Let’s take this further by writing some code to tell us when the next showing of a movie is. Our function’s going to take a movie as an argument, and return a string containing the next time it plays, based on your current time.

image with no caption
image with no caption

Testing at the drive-in

image with no caption

Get the code on the previous page typed in and let’s give it a test run. You’ll see that the getNextShowing function takes whatever movie it is handed and figures out the next showing time. Feel free to create some new movie objects of your own and give them a test drive too. We did, at our own local time of 12:30pm:

image with no caption

Objects can have behavior too...

You didn’t think objects were just for storing numbers, strings and arrays did you? Objects are active, they can do things. Dogs don’t just sit there: they bark, run, play catch and a dog object should too! Given everything you’ve learned in this chapter, you’re all set to add behavior to your objects. Here’s how we do that:

image with no caption

When an object has a function in it, we say that object has a method.

To call a method on an object we use the object name along with the method using our dot notation, and supply any arguments needed.

image with no caption

Meanwhile back at Webville Cinema...

Now that your knowledge of objects is expanding we can go back and improve the cinema code. We’ve already written a getNextShowing function that takes a movie as an argument, but we could instead make this part of the movie object by making it a method. Let’s do that:

image with no caption
image with no caption

But we know that can’t be quite right...

We actually can’t just throw the function in this object because getNextShowing takes a movie argument, and what we really want is to call getNextShowing like this:

image with no caption

Alright, so how do we fix this? We’ve got to remove the parameter from the getNextShowing method definition, but then we need to do something with all the references to movie.showtimes in the code because, once we remove the parameter, movie will no longer exist as a variable. Let’s take a look...

Let’s get the movie parameter out of there...

We’ve taken the liberty of removing the movie parameter, and all the references to it. Which leaves us with this code:

image with no caption

Now what?

Alright, here’s the conundrum: we’ve got these references to the properties showtimes and title. Normally in a function we’re referencing a local variable, a global variable, or a parameter of the function, but showtimes and title are properties of the movie1 object. Well maybe this just works... it seems like JavaScript might be smart enough to figure this out?

Nope. It doesn’t work. Feel free to give it a test drive; JavaScript will tell you the showtimes and title variables are undefined. How can that be?

Okay, here’s the deal: these variables are properties of an object, but we aren’t telling JavaScript which object. You might say to yourself, “Well, obviously we mean THIS object, this one right here! How could there be any confusion about that?” And, yes, we want the properties of this very object. In fact, there’s a keyword in JavaScript named this, and that is exactly how you tell JavaScript you mean this object we’re in.

Now, the situation is actually a little more complicated than it appears here, and we’re going to get to that in a second, but for now we’re going to add the this keyword and get this code working.

Adding the “this” keyword

Let’s add this each place we specify a property, so that we’re telling JavaScript we want the property in this object:

image with no caption

A test drive with “this”

image with no caption

Go ahead and type in the code above and also add the getNextShowing function to your movie2 object (just copy and paste it in). Then make the changes below to your previous test code. After that give it a spin! Here’s what we got:

image with no caption
image with no caption
image with no caption

Ah, good eye.

You have great instincts if you recognized that we are duplicating code when we copy getNextShowing into more than one movie object. One of the aims of “object-oriented” programming is to maximize code reuse—here we’re not reusing any code, in fact we’re creating every object as a one-off, and our movie objects just happen to be the same by convention (and copying and pasting!). Not only is that a waste, it can be error prone.

There’s a much better way to do this using a constructor. What’s a constructor? It’s just a special function we’re going to write that can create objects for us, and make them all the same. Think of it like a little factory that takes the property values you want to set in your object, and then hands you back a nice new object with all the right properties and methods.

Let’s create a constructor...

How to create a constructor

Let’s make a constructor for dogs. We already know what we want our dog objects to look like: they have name, breed and weight properties, and they have a bark method. So what our constructor needs to do is take the property values as parameters and then hand us back a dog object all ready to bark. Here’s the code:

image with no caption

So let’s walk through this again to make sure we’ve got it. Dog is a constructor function and it takes a set of arguments, which just happen to be the initial values for the properties we want: name, breed and weight. Once it has those values, it assigns properties using the this keyword. It also defines our bark method. The result of all this? The Dog constructor returns a new object. Let’s see how to actually use the constructor.

Now let’s use our constructor

image with no caption

Now that we’ve got our factory built, we can use it to create some dogs. There’s only one thing we haven’t told you, which is that you need to call a constructor function in a special way by putting the keyword new before the call. Here are some examples:

image with no caption

Let’s review what’s going on here one more time: we’re creating three different dog objects, each with its own properties, using the new keyword with the Dog constructor that we created. The constructor returns a Dog object customized with the arguments we passed in.

Next, we call the bark method on each one—notice that we’re sharing the same bark method across all dogs, and when each dog barks, this points to the dog object that made the call. So if we call the bark method on fido, then, in the bark method, this is set to the fido object. Let’s look a little closer at how that happens.

How does this really work?

Behind the Scenes

image with no caption

Anytime we put this in the code of a method it will be interpreted as a reference to the object the method was called on. So, if we call fido.bark, then this is going to reference fido. Or, if we call it on our dog object tiny then this is going to reference tiny within that method call. How does this know which object it is representing? Let’s see:

  1. Let’s say we’ve got a dog object assigned to fido:

    image with no caption
  2. And we call bark() on fido:

    image with no caption
  3. So “this” always refers to the object the method was invoked on, no matter how many dogs we create to bark:

    image with no caption

Test drive your constructor right off the factory floor

image with no caption

Now that you’ve got a Movie constructor, it’s time to make some Movie objects! Go ahead and type in the Movie constructor function and then add the code below and take your constructor for a spin. We think you’ll agree this a much easier way to create objects.

image with no caption
image with no caption

Now, you might have started to notice...

...that objects are all around you. For instance, document and window are objects, as are the elements we get back from document.getElementById. And, these are just a few of many objects we’ll be encountering—when we get to the HTML5 APIs, we’ll be seeing objects everywhere!

Let’s take a second look at some of the objects you’ve been using all along in this book:

image with no caption

What is the window object anyway?

When you’re writing code for the browser, the window object is always going to be part of your life. The window object represents both the global environment for your JavaScript programs and the main window of your app, and as such, it contains many core properties and methods. Let’s take a look at it:

image with no caption
image with no caption
image with no caption

Window is the global object.

It may seem a little weird, but the window object acts as your global environment, so the names of any properties or methods from window are resolved even if you don’t prepend them with window.

In addition, any global variables you define are also put into the window namespace, so you can reference them as window.myvariable.

A closer look at window.onload

One thing we’ve used often so far in this book is a window.onload event handler. By assigning a function to the window.onload property, we can ensure our code isn’t run until the page is loaded and the DOM is completely set up. Now, there’s a lot going on in the window.onload statement, so let’s have another look and it will all start to come together for you:

image with no caption

Another look at the document object

The document object is another familar face; it’s the object we’ve been using to access the DOM. And, as you’ve just seen, it is actually a property of the window object. Of course we haven’t used it like window.document because we don’t need to. Let’s take a quick peek under the covers to see its more interesting properties and methods:

image with no caption

A closer look at document.getElementById

We promised in the begining of this chapter that you’d understand document.getElementById by the end of the chapter. Well, you made it through functions, objects, and methods, and now you’re ready! Check it out:

image with no caption
image with no caption

What was a confusing looking string of syntax now has a lot more meaning, right? Now, that div variable is also an object: an element object. Let’s take a closer look at that too.

One more object to think about: your element objects

We shouldn’t forget when we’re working with methods like getElementById that the elements they return are also objects! Okay, you might not have realized this, but now that you know, you might be starting to think everything in JavaScript is an object, and, well, you’re pretty much right.

You’ve already seen some evidence of element properties, like the innerHTML property; let’s look at some of the more notable properties and methods:

image with no caption

Note

Yes, String is an object! Check out a good JavaScript reference to get all the details of its properties and methods.

image with no caption

Get Head First HTML5 Programming now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.