use
typeof v
to identify functions. Note, however, that if
v
is a function,
v instan
ceof Object
will be true, so if you are trying to distinguish between functions and
other types of objects, you’ll want to test
typeof
first.
IIFEs and Asynchronous Code
We were introduced to IIFEs (immediately invoked function expressions) in
, and we saw that they were a way of creating a closure. Let’s look at an important
example (one that we will revisit in
) of how IIFEs can help us with asyn‐
chronous code.
One of the first uses of IIFEs was to create new variables in new scopes so that asyn‐
chronous code would run correctly. Consider the classic example of a timer that starts
at 5 seconds and counts down to “go!” (0 seconds). This code uses the built-in func‐
tion
setTimeout
, which delays the execution of its first argument (a function) by its
second argument (some number of milliseconds). For example, this will print out
hello
after 1.5 seconds:
setTimeout
(
function
() {
console
.
log
(
"hello"
); },
1500
);
Now that we’re armed with that knowledge, here’s our countdown function:
var
i
;
for
(
i
=
5
;
i
>=
0
;
i
--
) {
setTimeout
(
function
() {
console
.
log
(
i
===
0
?
"go!"
:
i
);
}, (
5
-
i
)
*
1000
);
}
Take note that we’re using
var
instead of
let
here; we’re having to step back in time to
understand why IIFEs were important. If you expect this to print out
5, 4, 3, 2,
1, go!
, you will be disappointed. Instead, you will find
–1
printed out six times.
What’s happening here is that the function being passed to
setTimeout
is not invoked
in the loop: it will be invoked at some point in the future. So the loop will run, and
i
will start at 5, and eventually reach –1…all before any of the functions are invoked. So
by the time the functions are invoked, the value of
i
is
–1
.
Even though block-level scope (with
let
variables) essentially solves this problem,
this is still a very important example if you’re new to asynchronous programming. It
can be hard to wrap your head around, but it’s critical to understanding asynchro‐
nous execution (the subject of
Before block-scoped variables, the way to solve this problem would have been to use
another function. Using an additional function creates a new scope, and the value of
i
can be “captured” (in a closure) at each step. Consider first using a named function:
IIFEs and Asynchronous Code | 189