Page 1: A Simple Example
We’ll work up from the pieces, just to remember the JavaScript basics.
Functions in JavaScript
We want to write a program that responds when a button is pressed. This requires use to define a “handler” (or “callback”) function that is called when the button is clicked.
F-01-01.html and F-01-01.js are a very simple program that does something when the button is pressed.
Before trying it, read the code and make sure you can predict what it is going to do:
|
|
A few things to notice…
- Line 1 declares a
const
variable namedbutton
. We declare it as aconst
since we know it isn’t going to change. We could have made it a regular variable by usinglet
instead. By declaring it as const we tell the compiler that it won’t change, so the compiler can warn us if we try to change it by mistake. It also provides documentation to the reader of the program that this variable won’t change value. - The
button
variable is file scoped. You can think of it as a global variable (but global to this file). - Line 2 declares function called
handler
. When the function is called, line 3 is executed. - Line 3 is only executed when
handler
is called. It uses that “global” (file scoped) variable that we defined back on line 1. Functions have access to variables defined above them (assuming they aren’t in some local scope). - Line 3 assigns the value “Changed !” to the
innerHTML
slot (member variable) of button (which we assume is an object that has aninnerHTML
slot). - Line 5 assigns the
handler
function to theonclick
slot of button. - I just happened to know that if you assign a function to the
onclick
slot of a button, it will get called when the button is pressed.
That last step deserves some mention. We should think of the handler
function as a special kind of object. Line 5 assigns that object (or a reference to that object) to the member variable.
Javascript lets us re-write line 2 in a different way that might make this clearer:
|
|
This is equivalent, but exposes what function declaration does. Think about declaring a function as the function
keyword is a function that runs the compiler (on the code that follows it) and returns a “function object”. In this case, we assign that object to the variable handler
.
Getting used to this idea that a function is just an object is important in JavaScript.
Because we are just using this function in one place, we don’t even need to both to assign it to a variable or give it a name. We can simply assign it directly to the slot where we need it:
|
|
The important thing here: functions are just objects, just like strings and numbers and buttons. They can be created, assigned to variables, passed as arguments to functions, …
Arguments
Let’s make an html file with two buttons (F-01-02.html), and extend the first example.
Here is that code applied to both buttons. Since I am using the function twice, it is useful to store it in a variable, although I could have written button2.onclick = button1.onclick
.
|
|
Again, understand what this program F-01-02.js does before trying it. It doesn’t do what you probably would want it to do.
Suppose we wanted the button clicked to change itself. We could define different functions for each button, that would be painful if we had lots of buttons, or if the code that the buttons had to run was complicated.
A better answer is to take advantage of the fact that handlers get an “event” object as an argument, and the “event” object know what html element is getting the event. So, F-01-03.html F-01-03.js will do the “right” thing.
The changed lines:
|
|
Show you that you that event handler functions receive an argument (that is the event), and that these events have target elements.
You might wonder, “why did the previous version work at all?” In the example above (F-01-02.js) the button click did pass the event argument to the handler function - the handler function just ignored it (by not taking any arguments).
A Gratuitous Closure
Warning: this section might not make sense at first. It will make more sense after the next few pages. The idea here is that you can see a closure, which will hopefully motivate you to understand why this works and how you can use it (which the following pages explain).
How could we have written the previous program if we didn’t know about events?
Here’s one way: (the code is F-01-04.js)
|
|
The most obvious difference here is that we are defining a function setHandler
that “sets up” a button. It takes a button as an argument, and sets the onclick
slot of the button.
There are (at least) two things here that may be slightly weird:
- We define a function inside of the function. Line 5 effectively runs the compiler each time the
setHandler
function is called. BecausesetHandler
is called twice (lines 11 and 12), the compiler will compile that code twice. A good compiler is probably smart enough that it probably doesn’t actually compile the code multiple times, but conceptually, you can think about the compiler being run twice. - The inner
handler
function uses thebutton
variable that belongs tosetHandler
. Arguments (likebutton
) are just variables, and obey the same scoping rules.
This is a little tricky. Basically, for each button, we call setHandler
to set it up. setHandler
knows which button it is working on, because it has the button in its button
parameter. setHandler
runs the compiler and makes a new version of the handler function that it assigns to the button. This version has the right value for button
.
When we ran the compiler on line 5, the value of button
had an appropriate value. That value was “enclosed” inside of the function object that was created. This idea of enclosing variables when functions are defined is called closure.
If you need to be convinced that this works:
The important concept here is that when we define a function, that function has access to the variables “around it” (defined above and outside the function). You can access “global” (or file scoped variables). And, you can access variables in enclosing scopes.
Summary of Page 1
The lessons here:
- Think of functions as objects that are created, stored in variables, passed as function arguments - just like other objects.
- Think of the
function
keyword as something that runs the compiler on the code (while the script is executing) and produces a value (a function object) - When a function object is created, it remembers the variables that enclose it. (it actually remembers the variables, not the values - but we’ll see that on a later page)
On the next page we’ll review the concept of scope to get a better sense of what is enclosed.
Next: Variables and Scope