You are on page 1of 10

Closures

Closures are functions that refer to independent (free) variables. In short, variables from the parent function of the closure remain bound from the parent's scope. Consider the following:

f u n c t i o ni n i t ( ){ v a rn a m e=" M o z i l l a " ;/ /n a m ei sal o c a lv a r i a b l ec r e a t e db yi n i t d i s p l a y N a m e ( ){/ /d i s p l a y N a m e ( )i st h ei n n e rf u n c t i o n ,ac l o s u r e / /d i s p l a y N a m e ( )u s e sv a r i a b l ed e c l a r e di nt h ep a r e n tf u n c t i o n d i s p l a y N a m e ( ) ; } i n i t ( ) ; } f u n c t i o n a l e r t( n a m e ) ;

i n i t ( )creates a local variable n a m eand then a function called d i s p l a y N a m e ( ) .d i s p l a y N a m e ( ) is the inner function (a closure) it is defined inside i n i t ( ) , and only available within the body of that function . Unlike i n i t ( ) ,d i s p l a y N a m e ( )has no local variables of its own, and instead reuses the variable n a m edeclared in the parent function. Run the code and see that this works. This is an example of lexical scoping: in JavaScript, the scope of a variable is defined by its location within the source code (it is apparent lexically) and nested functions have access to variables declared in their outer scope. Now consider the following example:

f u n c t i o nm a k e F u n c ( ){ v a rn a m e=" M o z i l l a " ; f u n c t i o nd i s p l a y N a m e ( ){ a l e r t ( n a m e ) ; } r e t u r nd i s p l a y N a m e ;

} v a rm y F u n c=m a k e F u n c ( ) ; m y F u n c ( ) ;

If you run this code it will have exactly the same effect as the previous i n i t ( )example: the string "Mozilla" will be displayed in a JavaScript alert box. What's different and interesting is that the d i s p l a y N a m e ( )inner function was returned from the outer function before being executed. That the code still works may seem unintuitive. Normally, the local variables within a function only exist for the duration of that function's execution. Once m a k e F u n c ( )has finished executing, it is reasonable to expect that the name variable will no longer be accessible. Since the code still works as expected, this is obviously not the case. The solution to this puzzle is that m a k e F u n chas become a closure. A closure is a special kind of object that combines two things: a function, and the environment in which that function was created. The environment consists of any local variables that were in-scope at the time that the closure was created. In this case, m y F u n cis a closure that incorporates both the d i s p l a y N a m e function and the "Mozilla" string that existed when the closure was created. Here's a slightly more interesting example a m a k e A d d e rfunction:

f u n c t i o nm a k e A d d e r ( x ){ r e t u r nf u n c t i o n ( y ){ r e t u r nx+y ; } ; } v a ra d d 5=m a k e A d d e r ( 5 ) ; v a ra d d 1 0=m a k e A d d e r ( 1 0 ) ; c o n s o l e . l o g ( a d d 5 ( 2 ) ) ; / /7 c o n s o l e . l o g ( a d d 1 0 ( 2 ) ) ;/ /1 2

In this example, we have defined a function m a k e A d d e r ( x )which takes a single argument xand returns a new function. The function it returns takes a single argument y , and returns the sum of xand y . In essence, m a k e A d d e ris a function factory it creates functions which can add a specific value to their argument. In the above example we use our function factory to create two new functions one that adds 5 to its argument, and one that adds 10.

a d d 5and a d d 1 0are both closures. They share the same function body definition, but store different environments. In a d d 5 's environment, xis 5. As far as a d d 1 0is concerned, xis 10.

Practical closures
That's the theory out of the way but are closures actually useful? Let's consider their practical implications. A closure lets you associate some data (the environment) with a function that operates on that data. This has obvious parallels to object oriented programming, where objects allow us to associate some data (the object's properties) with one or more methods. Consequently, you can use a closure anywhere that you might normally use an object with only a single method. Situations where you might want to do this are particularly common on the web. Much of the code we write in web JavaScript is event-based we define some behavior, then attach it to an event that is triggered by the user (such as a click or a keypress). Our code is generally attached as a callback: a single function which is executed in response to the event. Here's a practical example: suppose we wish to add some buttons to a page that adjust the text size. One way of doing this is to specify the font-size of the body element in pixels, then set the size of the other elements on the page (such as headers) using the relative em unit:

b o d y{ f o n t f a m i l y :H e l v e t i c a ,A r i a l ,s a n s s e r i f ; f o n t s i z e :1 2 p x ; } h 1{ f o n t s i z e :1 . 5 e m ; } h 2{ f o n t s i z e :1 . 2 e m ; }

Our interactive text size buttons can change the font-size property of the body element, and the adjustments will be picked up by other elements on the page thanks to the relative units. Here's the JavaScript:

f u n c t i o nm a k e S i z e r ( s i z e ){ r e t u r nf u n c t i o n ( ){

d o c u m e n t . b o d y . s t y l e . f o n t S i z e=s i z e+' p x ' ; } ; } v a rs i z e 1 2=m a k e S i z e r ( 1 2 ) ; v a rs i z e 1 4=m a k e S i z e r ( 1 4 ) ; v a rs i z e 1 6=m a k e S i z e r ( 1 6 ) ;

s i z e 1 2 ,s i z e 1 4 , and s i z e 1 6are now functions which will resize the body text to 12, 14, and 16 pixels, respectively. We can attach them to buttons (in this case links) as follows:

d o c u m e n t . g e t E l e m e n t B y I d ( ' s i z e 1 2 ' ) . o n c l i c k=s i z e 1 2 ; d o c u m e n t . g e t E l e m e n t B y I d ( ' s i z e 1 4 ' ) . o n c l i c k=s i z e 1 4 ; d o c u m e n t . g e t E l e m e n t B y I d ( ' s i z e 1 6 ' ) . o n c l i c k=s i z e 1 6 ;

< ah r e f = " # "i d = " s i z e 1 2 " > 1 2 < / a > < ah r e f = " # "i d = " s i z e 1 4 " > 1 4 < / a > < ah r e f = " # "i d = " s i z e 1 6 " > 1 6 < / a >

VIEW ON JSFIDDLE

Emulating private methods with closures


Languages such as Java provide the ability to declare methods private, meaning that they can only be called by other methods in the same class. JavaScript does not provide a native way of doing this, but it is possible to emulate private methods using closures. Private methods aren't just useful for restricting access to code: they also provide a powerful way of managing your global namespace, keeping non-essential methods from cluttering up the public interface to your code. Here's how to define some public functions that can access private functions and variables, using closures which is also known as the module pattern:

v a rC o u n t e r=( f u n c t i o n ( ){ v a rp r i v a t e C o u n t e r=0 ;

f u n c t i o nc h a n g e B y ( v a l ){ p r i v a t e C o u n t e r+ =v a l ; } r e t u r n{ i n c r e m e n t :f u n c t i o n ( ){ c h a n g e B y ( 1 ) ; } , d e c r e m e n t :f u n c t i o n ( ){ c h a n g e B y ( 1 ) ; } , v a l u e :f u n c t i o n ( ){ r e t u r np r i v a t e C o u n t e r ; } } ; } ) ( ) ; a l e r t ( C o u n t e r . v a l u e ( ) ) ;/ *A l e r t s0* / C o u n t e r . i n c r e m e n t ( ) ; C o u n t e r . i n c r e m e n t ( ) ; a l e r t ( C o u n t e r . v a l u e ( ) ) ;/ *A l e r t s2* / C o u n t e r . d e c r e m e n t ( ) ; a l e r t ( C o u n t e r . v a l u e ( ) ) ;/ *A l e r t s1* /

There's a lot going on here. In previous examples each closure has had its own environment; here we create a single environment which is shared by three functions: C o u n t e r . i n c r e m e n t , C o u n t e r . d e c r e m e n t , and C o u n t e r . v a l u e . The shared environment is created in the body of an anonymous function, which is executed as soon as it has been defined. The environment contains two private items: a variable called p r i v a t e C o u n t e rand a function called c h a n g e B y . Neither of these private items can be accessed directly from outside the anonymous function. Instead, they must be accessed by the three public functions that are returned from the anonymous wrapper. Those three public functions are closures that share the same environment. Thanks to JavaScript's lexical scoping, they each have access to the p r i v a t e C o u n t e rvariable and c h a n g e B yfunction. You'll notice we're defining an anonymous function that creates a counter, and then we call it immediately and assign the result to the C o u n t e rvariable. We could store this function in a separate variable and use it to create several counters.

v a rm a k e C o u n t e r=f u n c t i o n ( ){ v a rp r i v a t e C o u n t e r=0 ;

f u n c t i o nc h a n g e B y ( v a l ){ p r i v a t e C o u n t e r+ =v a l ; } r e t u r n{ i n c r e m e n t :f u n c t i o n ( ){ c h a n g e B y ( 1 ) ; } , d e c r e m e n t :f u n c t i o n ( ){ c h a n g e B y ( 1 ) ; } , v a l u e :f u n c t i o n ( ){ r e t u r np r i v a t e C o u n t e r ; } } } ; v a rC o u n t e r 1=m a k e C o u n t e r ( ) ; v a rC o u n t e r 2=m a k e C o u n t e r ( ) ; a l e r t ( C o u n t e r 1 . v a l u e ( ) ) ;/ *A l e r t s0* / C o u n t e r 1 . i n c r e m e n t ( ) ; C o u n t e r 1 . i n c r e m e n t ( ) ; a l e r t ( C o u n t e r 1 . v a l u e ( ) ) ;/ *A l e r t s2* / C o u n t e r 1 . d e c r e m e n t ( ) ; a l e r t ( C o u n t e r 1 . v a l u e ( ) ) ;/ *A l e r t s1* / a l e r t ( C o u n t e r 2 . v a l u e ( ) ) ;/ *A l e r t s0* /

Notice how each of the two counters maintains its independence from the other. Its environment during the call of the m a k e C o u n t e r ( )function is different each time. The closure variable p r i v a t e C o u n t e r contains a different instance each time. Using closures in this way provides a number of benefits that are normally associated with object oriented programming, in particular data hiding and encapsulation.

Creating closures in loops: A common mistake


Prior to the introduction of the l e tkeyword in JavaScript 1.7, a common problem with closures occurred when they were created inside a loop. Consider the following example:

< pi d = " h e l p " > H e l p f u ln o t e sw i l la p p e a rh e r e < / p > < p > E m a i l :< i n p u tt y p e = " t e x t "i d = " e m a i l "n a m e = " e m a i l " > < / p > < p > N a m e :< i n p u tt y p e = " t e x t "i d = " n a m e "n a m e = " n a m e " > < / p > < p > A g e :< i n p u tt y p e = " t e x t "i d = " a g e "n a m e = " a g e " > < / p >

f u n c t i o ns h o w H e l p ( h e l p ){ d o c u m e n t . g e t E l e m e n t B y I d ( ' h e l p ' ) . i n n e r H T M L=h e l p ; } f u n c t i o ns e t u p H e l p ( ){ v a rh e l p T e x t=[ { ' i d ' :' e m a i l ' ,' h e l p ' :' Y o u re m a i la d d r e s s ' } , { ' i d ' :' n a m e ' ,' h e l p ' :' Y o u rf u l ln a m e ' } , { ' i d ' :' a g e ' ,' h e l p ' :' Y o u ra g e( y o um u s tb eo v e r1 6 ) ' } ] ; f o r( v a ri=0 ;i<h e l p T e x t . l e n g t h ;i + + ){ v a ri t e m=h e l p T e x t [ i ] ; d o c u m e n t . g e t E l e m e n t B y I d ( i t e m . i d ) . o n f o c u s=f u n c t i o n ( ){ s h o w H e l p ( i t e m . h e l p ) ; } } } s e t u p H e l p ( ) ;

VIEW ON JSFIDDLE

The h e l p T e x tarray defines three helpful hints, each associated with the ID of an input field in the document. The loop cycles through these definitions, hooking up an onfocus event to each one that shows the associated help method. If you try this code out, you'll see that it doesn't work as expected. No matter what field you focus on, the message about your age will be displayed. The reason for this is that the functions assigned to onfocus are closures; they consist of the function definition and the captured environment from the s e t u p H e l pfunction's scope. Three closures have been created, but each one shares the same single environment. By the time the onfocus callbacks are executed, the loop has run its course and the item variable (shared by all three closures) has been left pointing to the last entry in the h e l p T e x tlist. One solution in this case is to use more closures: in particular, to use a function factory as described earlier on:

f u n c t i o ns h o w H e l p ( h e l p ){ d o c u m e n t . g e t E l e m e n t B y I d ( ' h e l p ' ) . i n n e r H T M L=h e l p ; }

f u n c t i o nm a k e H e l p C a l l b a c k ( h e l p ){ r e t u r nf u n c t i o n ( ){ s h o w H e l p ( h e l p ) ; } ; } f u n c t i o ns e t u p H e l p ( ){ v a rh e l p T e x t=[ { ' i d ' :' e m a i l ' ,' h e l p ' :' Y o u re m a i la d d r e s s ' } , { ' i d ' :' n a m e ' ,' h e l p ' :' Y o u rf u l ln a m e ' } , { ' i d ' :' a g e ' ,' h e l p ' :' Y o u ra g e( y o um u s tb eo v e r1 6 ) ' } ] ; f o r( v a ri=0 ;i<h e l p T e x t . l e n g t h ;i + + ){ v a ri t e m=h e l p T e x t [ i ] ; d o c u m e n t . g e t E l e m e n t B y I d ( i t e m . i d ) . o n f o c u s=m a k e H e l p C a l l b a c k ( i t e m . h e l p ) ; } } s e t u p H e l p ( ) ;

VIEW ON JSFIDDLE

This works as expected. Rather than the callbacks all sharing a single environment, the m a k e H e l p C a l l b a c kfunction creates a new environment for each one in which h e l prefers to the corresponding string from the h e l p T e x tarray.

Performance considerations
It is unwise to unnecessarily create functions within other functions if closures are not needed for a particular task, as it will negatively affect script performance both in terms of processing speed and memory consumption. For instance, when creating a new object/class, methods should normally be associated to the object's prototype rather than defined into the object constructor. The reason is that whenever the constructor is called, the methods would get reassigned (that is, for every object creation). Consider the following impractical but demonstrative case:

f u n c t i o nM y O b j e c t ( n a m e ,m e s s a g e ){ t h i s . n a m e=n a m e . t o S t r i n g ( ) ;

t h i s . m e s s a g e=m e s s a g e . t o S t r i n g ( ) ; t h i s . g e t N a m e=f u n c t i o n ( ){ r e t u r nt h i s . n a m e ; } ; t h i s . g e t M e s s a g e=f u n c t i o n ( ){ r e t u r nt h i s . m e s s a g e ; } ; }

The previous code does not take advantage of the benefits of closures and thus should instead be formulated:

f u n c t i o nM y O b j e c t ( n a m e ,m e s s a g e ){ t h i s . n a m e=n a m e . t o S t r i n g ( ) ; t h i s . m e s s a g e=m e s s a g e . t o S t r i n g ( ) ; } M y O b j e c t . p r o t o t y p e={ g e t N a m e :f u n c t i o n ( ){ r e t u r nt h i s . n a m e ; } , g e t M e s s a g e :f u n c t i o n ( ){ r e t u r nt h i s . m e s s a g e ; } } ;

Or as follows:

f u n c t i o nM y O b j e c t ( n a m e ,m e s s a g e ){ t h i s . n a m e=n a m e . t o S t r i n g ( ) ; t h i s . m e s s a g e=m e s s a g e . t o S t r i n g ( ) ; } M y O b j e c t . p r o t o t y p e . g e t N a m e=f u n c t i o n ( ){ r e t u r nt h i s . n a m e ; } ; M y O b j e c t . p r o t o t y p e . g e t M e s s a g e=f u n c t i o n ( ){ r e t u r nt h i s . m e s s a g e ; } ;

In the two previous examples, the inherited prototype can be shared by all objects and the method definitions need not occur at every object creation. See Details of the Object Model for more details.

Previous

Next

You might also like