JavaScript Pop Quiz Remarks
Here's an email I sent in response to a colleague's question about some sample JavaScript. If you haven't already seen it, you might want to look at the code first.Joe:
You seem to understand the behaviour perfectly. The problem was that we wanted to call
set_datetime(...) with a different value for each cell in the table. We know the values when we build the table cell by cell.
However, if we write the code as:
thisCell.onclick =
function() { set_datetime( dt_current_day.valueOf(), true);
At run time each cell will have a function that gets the value of
dt_current_day when the cell is clicked, not when the code was written into the cell. I think we end up with the last day in the calendar. We want to capture the value when of
dt_current_day when we build the function, not later when the function is called.
The code given makes an anonymous function (let's call it the "outer function") and calls it immediately. That call copies
dt_current_day.valueOf() into the
day variable and returns a function (the "inner function") that uses the
day variable. The inner function is the one assigned to the cell's
onclick handler.
The reason it works is that every time you call the outer function you manufacture a new
day variable. If you did the assignment without calling a function, like this:
var day = dt_current_day.valueOf();
thisCell.onclick =
function() { set_datetime( day, true);
...you would end up with the wrong behaviour because all of the
onclick handlers would share the same day variable.
This pattern is so common that Lisp-like languages (including
Scheme) have a family of
macros called
let to do this for us. In Scheme, our code would look something like this:
(let (
(day (value-of dt_current_day)))
(!set (handler thisCell 'onclick)
(lambda () (set-datetime! day #t))))
Although using
let looks just like a straightforward assignment using
set!, it actually creates a new variable every time. It should not surprise you to learn (if you didn't already know) that behind the scenes
let is a macro that rewrites the code into an anonymous outer function just like the JavaScript sample.
p.s. This problem can be solved in other ways. The original code actually wrote the
onclick handler out as an
href in plain text. It copied the value of
dt_current_date out as a string. Essentially, it was doing "code generation." Also, it would be possible to create an object with a field to store the date. You'd have to do that in a language like Java where functions don't really exist independently of objects and classes.
p.p.s. I can't believe I managed to explain the whole thing without resorting to the
c-word!