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
Okay, first we need a function.
Let’s say you’ve just written your new
bark function, which has two parameters,
dogWeight, and also a very impressive bit of code that returns a dog’s bark, depending on its weight of course.
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:
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
dogWeight are assigned to the arguments you passed into the function.
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:
Remember, functions aren’t required to return a value. But in this case, the bark function does return a value.
When you define a function you can define it with one or more parameters.
When you call a function, you call it with arguments:
So you’ll only define your parameters once, but you’ll probably call your functions with a lot of different arguments.
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.
And you’ve seen that you can also declare variables inside a function:
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).
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:
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:
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.
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?
Here’s what that means: say you have a global variable
beanCounter and you then declare a function, like this:
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).
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:
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:
Or we could get even fancier:
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.
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.
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:
Likewise, you can delete any property with the
delete keyword, like this:
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
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).
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.
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...
Let’s take a look at what’s going on when we pass
loseWeight and change the
Behind the Scenes
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.
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:
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:
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.
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:
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:
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...
Alright, here’s the conundrum: we’ve got these references to the properties
title. Normally in a function we’re referencing a local variable, a global variable, or a parameter of the function, but
title are properties of the
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.
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:
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...
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:
So let’s walk though 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 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:
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.
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
this is going to reference
fido. Or, if we call it on our dog object
this is going to reference
tiny within that method call. How does
this know which object it is representing? Let’s see:
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.
...that objects are all around you. For instance,
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:
When you’re writing code for the browser, the
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
In addition, any global variables you define are also put into the window namespace, so you can reference them as
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:
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:
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:
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.
We shouldn’t forget when we’re working with methods like
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: