Another great question from a reader of Head First HTML5 Programming is about passing functions as values. This comes up when using the Geolocation API: the way you get your location is to call the built-in function getCurrentPosition()
and pass in two arguments, both of which are functions. The reader asks:
When you call
getCurrentPosition(displayLocation, displayError)
, how are you able to call the functiondisplayLocation()
from within the parameters of this method, and when you call it, how does it know to how to pass the position object todisplayLocation()
when you didn’t pass any parameters when you called it?
When you write getCurrentPosition(displayLocation, displayError)
, you are not calling the displayLocation
and displayError
functions, you are passing them as values! I know it seems odd to pass a function as a value, but that is actually one of the powerful things about JavaScript (not all programming languages allow you to do this!). Think of the parameters displayLocation
and displayError
as names for values, just like any other parameter that expects a value (whether that’s a number, a string, an object, or a function!). Because getCurrentPosition()
is a function built-in to JavaScript (and part of the Geolocation API), rather than one you write yourself, you don’t see getCurrentPosition()
actually calling those functions. If you could see inside getCurrentPosition()
, you’d see it call one of the functions, say displayLocation(position)
, and of course it would be passing in your position (as an object).
You can write your own functions that take other functions as arguments. For example:
function f(g) { return g(1); } function add1(x) { return x + 1; } f(add1);
You’ll get 2. Kind of mind-bendy, right? So what’s happening here is that you are creating two functions: add1
takes a number, x
, and adds 1 to it and returns it. Function f
takes a function, which you give the name g
. f
calls g
, and passes a number, 1, into it.
So, when you pass the function value add1
to f
, f
uses the parameter name g
as the name for the function value (remember, JavaScript is pass by value!!) and calls g
, with the result that you get the number 2.
This topic of functions as values and passing functions to other functions is quite complex and deserves a more in-depth treatment for sure, and we just didn’t have room in Head First HTML5 Programming to delve into it. We’ll have to tackle that in an in-depth tutorial at some point! Let us know if that’s a topic you’d be interested in learning more about.
Hi Elisabeth
I just finished up Chapter 4 and am having a hard time grasping the concept of functions as values. The question on page 158 regarding why we don’t say window.onload = init() is the same question I have. The answer provided isn’t clear to me.
Here are the things that I keep thinking about:
window.onload = init says that when page has loaded run the init function.
However, if it was window.onload = init() the init function would run before the page was loaded and the result of that init function would be assigned to window.onload?
In your text it says the difference between using () and not has large ramifications. Could you please explain those differences. I’m just so confused because without the () the init function is still run. It seems like there is an order of operations coming into play depending on if the () is there or not. It would be great to have some kind of timeline step by step so I can visualize the differences in what is happening.
What is the value that a function passes? Is the value just the text of the function? Is it like handing a piano player sheet music (the function) but telling him not to play it(run) yet? So it’s like passing window.onload sheet music and saying here is what you are going to play once the onload method of the window object is true.
Hi Sam,
I can help you with this. Let’s first dissect the basics of a function and how they work in Javascript.
function foo () {
// Some action…
}
This is known as a “named function” in Javascript, so called because after the “function” keyword there is a name: “foo”. What happens under the covers in the Javascript interpreter is that an object is created that represents the function; this is placed on the memory heap. In the memory stack is a pointer to the function object, and this pointer is the name of the function. “foo” in our case.
Now, to execute our function we simply do this:
foo();
This tells the engine, “I want the object that foo points to to execute.” The interpreter looks up the correct object in the heap and then proceeds to execute it.
But because functions are just objects with a named pointer, we can do some pretty interesting things with it. Like this:
var bar = foo;
By leaving off the parens what I’ve done here is told the interpreter, “That object that ‘foo’ is pointing at, point ‘bar’ to it as well.” Let me illustrate the concept.
There are 100 cups on the table and one of them belongs to you. You know exactly which cup is yours, and so when either you want to take a drink or someone wants to fill up your cup, you know right where it is to perform these actions. Now, someone you are close with wants a cup. Instead of dirtying a new one, you tell the person which of the cups on the table belongs to you and so they can start using it.
This is a really rough approximation on how pointers work. Now that you hopefully understand this, let me answer your question.
1) window.onload = init();
2) window.onload = init;
1. This will execute “init” immediately, which most likely means before the page actually finishes loading, and whatever the return value of “init” is gets assigned to the onload event handler. In many cases, this means that the “init” function has fired premature, which could have unintentional side effects.
2) This creates a new pointer to the function that “init” points to. When the page is loaded, the Javascript engine performs this action:
window.onload();
And since “onload” points to the same function as “init”, it is almost as if the interpreter has called init() directly.
Hopefully that helps.
Daniel
Thanks Daniel, you beat me to it! Eric and I are also prepping a separate post on this topic as it’s a confusing one for many new JavaScript programmers.
Thanks for the question, Sam, and the answer, Daniel!
Thank you Daniel. I understand now. For me it is a bit odd to think of a function as an object though.
In the book, on page 142, it says “when an object has a function in it, we say that the object has a method”. Based on what you wrote above, I assume that methods themselves are also objects created by the interpreter and placed on the heap? So a method is really just an object within another object?
Elisabeth: That’s great news. I look forward to reading the post on the topic.
Yes, it certainly is odd. But once you get your mind wrapped around it, you can do some pretty incredible things.
You are correct in your assumption – functions are a type of object placed on a heap. And like all objects in JavaScript, functions can have additional variables bound to it. Consider this example:
function foo(words) {
console.log(foo.BAR + ‘: ‘ + words);
}
foo.BAR = ‘[Some static text]’;
foo(‘This is wickedly cool!’); // Prints [Some static text]: This is wickedly cool!
Experiment with this concept a bit, and I’m certain you’ll be amazed at the rather interesting things you can do with it.
Sure thing! Look forward to reading the post. Let Eric know that working for Ted isn’t the same without him shouting across offices. 😉