var x = [3, 2, 5];
var myFunc = function(y) {
y.length = 2;
y.sort()
};
myFunc(x);
console.log(x); //Writes [2, 3]
10.6 The Scope Chain and Closures
Professor: Closures are n ot the most trivial conc ept, but they are important in Java-
Script, so it’s good to b e at least familiar with the basic idea.
Consider the following function definition:
var count = function() {
var i = 0;
return function() {
return i++;
};
};
The first unusual thing you w ill notice is that one function is defined within the other.
If you haven’t been exposed to programming languages like C before, then this ma y
not even seem so strange to y ou, but anyway: If you want to understand what the
above code is all about, yo u should first u nderstand the scope chain.
You are already familiar w ith the basic scoping rules that JavaScript uses to search for
the closest variable a ccessible inside the current scope. If the current scope is global,
then it lo oks for a global variable with th at name. If, however, the scope is local,
then it first looks in the local scope and if there’s no local variable by that name, it
also looks in the global scope. The chain of the two objects—a function object and
the glo bal object—that define variables within the two mentioned scopes is called the
scope chain of that variable.
In the above example, I cr eated yet another scope when I defined a function within
a function, and added that function at the end of the existing scope c hain. When the
variable i is referenced with in the inner (anonymous) function body, the local scope
of that function is first checked for the definition of i. Since th e definition is not
found, the search continues down the scope chain. The next scope searc hed is the
scope of the c ount() function, where the definition of i is eventually found. The r eal
fun, however, begins when we a ctually invoke the count() function. Like this, for
example:
var countThis = count();
Mike: Doesn’t this only assign a reference to the cou nt() function to a variable
countThis?
10.6. The Scope Chain and Closures 201
Professor: I t does, but not a reference to the count() fu nction. Note that the expres-
sion count() is not a reference but a function invocation because it has parentheses
at the end. So, in fact, the return value of the count() function is assigned to the
variable countThi s, which is a reference to the inner anonymous function.
In JavaScript, not only a function definition but also a function invocation creates
a new function object. The new function object holds the local variables for that
specific invocation and is added to the existing scope chain, which represents the scope
for th at particular function invocation. T he trick of the count() function is that it
defines another fun ction within its body and retu rns a reference to it. As long as you
keep a reference to the returned anonymous function, the anonymous function object
persists in m emory and so must the count() function object because it is a part of the
anonymous function’s scope chain.
We can invoke the co unt() function once mor e, an d again store a refe rence to the
returned anonymous function, this time to a variable countThat:
var countThat = count();
By doing that, we c reate yet another scope chain and append it to the existing one.
Note that the existing scope chain only contains the global object because c ount() is
invoked within global scope. Exactly the same was true with th e first invocation of the
count() function, and we end up with two scope chains, bo th starting with the global
object. Here’s a n illustration of the two scope chains of the two objects crea te d by th e
two invocations of count().
global
count
var i;
countThis
count
var i;
countThat
The two gr ay areas represent scopes of both i variables, and countThis and count
That are references to the two anonymous function objects that we created when we
called count() two times. What we can do now is call any of the two anonymous
functions, which sit on the top of the two scope chains. A call of th e left one will
incremen t and return the left i and a call of the right one will increment and return the
right i. For example:
countThis(); //The left i is now 1
countThat(); //The right i is now 1
countThis(); //The left i is now 2
countThis(); //The left i is now 3
console.log(countThis());//Writes 3 and increments the left i to 4:
console.log(countThat());//Writes 1 and increments the right i to 2:
202 Meeting 10. Understa nding Functions
Maria: Let me check so mething. It looks like countThis and countThat refer to
one and the same function. In fact they are ref erences to two distinct objects, both
representin g the same function definition. If they are really distinct, then the next
expression should r eturn false:
countThis === countThat //Returns false
Professor: I t does indee d return fa lse.
Maria: Then you said that a function invocation also creates a function object. The
next code should therefore perform the same:
var count = function() {
var i = 0;
return i++;
};
var countThis = count;
var countThat = count;
countThis();
countThat();
countThis();
countThis();
console.log(countThis());
console.log(countThat());
Professor: Not really. To begin with, the variables countThis and countThat now
both refer to the same object, which is the count() function definition. It’s true that
when y ou invoke co unt() through either of the two referen ces, you c reate a new
object. But because you do not keep—and there’s no way you can keep—a reference
to that object, the object together with its local variable count() is deleted from the
memory as soon as the function execution finishes. Each one of the ab ove invocations
creates a new object, which ha s no memory of the past invocations of count(), and
therefore all invocations return zero.
In languages like C such behavior can be imp le mented using so-called static variables,
but JavaScript d oes not know static variables, so you must use closure s instead.
Mike: I guess that’s useful whenever you need to store the state of the program after
the last function call. But you can also use global variables for that, can’t you?
Professor: Technically, th at would work. But cluttering your prog ram with too many
global variables is a sure sign of bad sty le . The ma in reason for that is that global
variables a re accessible from everywhere a nd some buggy chunk of your code might
accidentally change the value of an important variable. If that important variable is
kept local and you pr ovide a spe cial function to control it, then unwanted changes to it
are much less likely. The rule of thumb is that you try to avoid global variables unless
there’s a really good reason for them.
Maria: You mentioned closures. What exactly is a closure?
10.6. The Scope Chain and Closures 203
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.110.119