-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
1574 lines (1405 loc) · 65.2 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title>Javascript Closures</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link href="../../faq.css" rel="stylesheet" type="text/css">
<link href="../notes.css" rel="stylesheet" type="text/css">
<style type="text/css">
CODE { white-space:nowrap; }
.scopeCh {
white-space:nowrap;
font-family:Courier, monospace;
}
</style>
</head>
<body>
<h1>Javascript Closures</h1>
<div id="faqNav">
<a href="../../">FAQ</a> > <a href="../">FAQ Notes</a>
</div>
<ul>
<li><a href="#clIntro">Introduction</a></li>
<li><a href="#clResO">The Resolution of Property Names on Objects</a>
<ul>
<li><a href="#clResA">Assignment of Values</a></li>
<li><a href="#clResR">Reading of Values</a></li>
</ul>
</li>
<li><a href="#clIRExSc">Identifier Resolution, Execution Contexts and scope chains</a>
<ul>
<li><a href="#clExCon">The Execution Context</a></li>
<li><a href="#clScCh">scope chains and [[scope]]</a></li>
<li><a href="#clIdRes">Identifier Resolution</a></li>
</ul>
</li>
<li><a href="#clClose">Closures</a>
<ul>
<li><a href="#clAtGb">Automatic Garbage Collection</a></li>
<li><a href="#clFrmC">Forming Closures</a></li>
</ul>
</li>
<li><a href="#clClDo">What can be done with Closures?</a>
<ul>
<li><a href="#clSto">Example 1: setTimeout with Function References</a></li>
<li><a href="#clObjI">Example 2: Associating Functions with Object Instance Methods</a></li>
<li><a href="#clEncap">Example 3: Encapsulating Related Functionality</a></li>
<li><a href="#clOtE">Other Examples</a></li>
</ul>
</li>
<li><a href="#clAc">Accidental Closures</a></li>
<li><a href="#clMem">The Internet Explorer Memory Leak Problem</a></li>
</ul>
<h2 id="clIntro">Introduction</h2>
<blockquote cite="http://groups.google.com/groups?selm=wu535hos.fsf@hotpop.com">
<dl>
<dt id="clDefN">Closure</dt>
<dd>A "closure" is an expression (typically a function) that
can have free variables together with an environment that binds
those variables (that "closes" the expression).
<dd>
</dl>
</blockquote>
<p>
Closures are one of the most powerful features of ECMAScript
(javascript) but they cannot be property exploited without
understanding them. They are, however, relatively easy to create,
even accidentally, and their creation has potentially harmful
consequences, particularly in some relatively common web browser
environments. To avoid accidentally encountering the drawbacks and
to take advantage of the benefits they offer it is necessary to
understand their mechanism. This depends heavily on the role of
scope chains in identifier resolution and so on the resolution of
property names on objects.
</p>
<p>
The simple explanation of a Closure is that ECMAScript allows inner
functions; function definitions and function expressions that are
inside the function bodes of other functions. And that those inner
functions are allowed access to all of the local variables, parameters
and declared inner functions within their outer function(s). A closure
is formed when one of those inner functions is made accessible outside
of the function in which it was contained, so that it may be executed
after the outer function has returned. At which point it still has
access to the local variables, parameters and inner function
declarations of its outer function. Those local variables, parameter
and function declarations (initially) have the values that they had
when the outer function returned and may be interacted with by the
inner function.
</p>
<p>
Unfortunately, properly understanding closures requires an
understanding of the mechanism behind them, and quite a bit of
technical detail. While some of the ECMA 262 specified algorithms have
been brushed over in the early part of the following explanation, much
cannot be omitted or easily simplified. Individuals familiar with
object property name resolution may skip that section but only people
already familiar with closures can afford to skip the following
sections, and they can stop reading now and get back to exploiting
them.
</p>
<h2 id="clResO">The Resolution of Property Names on Objects</h2>
<p>
ECMAScript recognises two categories of object, "Native Object"
and "Host Object" with a sub-category of native objects called
"Built-in Object" (ECMA 262 3rd Ed Section 4.3). Native objects
belong to the language and host objects are provided by the environment,
and may be, for example, document objects, DOM nodes and the like.
</p>
<p>
Native objects are loose and dynamic bags of named properties (some
implementations are not that dynamic when it comes to the built in
object sub-category, though usually that doesn't matter). The defined
named properties of an object will hold a value, which may be a
reference to another Object (functions are also Objects in this sense)
or a primitive value: String, Number, Boolean, Null or Undefined. The
Undefined primitive type is a bit odd in that it is possible to assign
a value of Undefined to a property of an object but doing so does not
remove that property from the object; it remains a defined named
property, it just holds the value <code>undefined</code>.
</p>
<p>
The following is a simplified description of how property values are
read and set on objects with the internal details brushed over to the
greatest extent possible.
</p>
<h3><a name="clResA" id="clResA">Assignment of Values</a></h3>
<p>
Named properties of objects can be created, or values set on existing
named properties, by assigning a value to that named property. So
given:-
</p>
<pre>
var objectRef = new Object(); <span class="commentJS">//create a generic javascript object.</span>
</pre>
<p>
A property with the name "testNumber" can be created as:-
</p>
<pre>
objectRef.testNumber = 5;
<span class="commentJS">/* - or:- */</span>
objectRef["testNumber"] = 5;
</pre>
<p>
The object had no "testNumber" property prior to the
assignment but one is created when the assignment is made. Any
subsequent assignment does not need to create the property, it just
re-sets its value:-
</p>
<pre>
objectRef.testNumber = 8;
<span class="commentJS">/* - or:- */</span>
objectRef["testNumber"] = 8;
</pre>
<p>
Javascript objects have prototypes that can themselves be objects, as
will be described shortly, and that prototype may have named
properties. But this has no role in assignment. If a value is assigned
and the actual object does not have a property with the corresponding
name a property of that name is created and the value is assigned to
it. If it has the property then its value is re-set.
</p>
<h3><a name="clResR" id="clResR">Reading of Values</a></h3>
<p>
It is in reading values from object properties that prototypes come
into play. If an object has a property with the property name used in
the property accessor then the value of that property is returned:-
</p>
<pre>
<span class="commentJS">/* Assign a value to a named property. If the object does not have a
property with the corresponding name prior to the assignment it
will have one after it:-
*/</span>
objectRef.testNumber = 8;
<span class="commentJS">/* Read the value back from the property:- */</span>
var val = objectRef.testNumber;
<span class="commentJS">/* and - val - now holds the value 8 that was just assigned to the
named property of the object. */</span>
</pre>
<p>
But all objects may have prototypes, and prototypes are objects so they, in
turn, may have prototypes, which may have prototypes, and so on forming
what is called the prototype chain. The prototype chain ends when one
of the objects in the chain has a null prototype. The default prototype for the
<code>Object</code> constructor has a null prototype so:-
</p>
<pre>
var objectRef = new Object(); <span class="commentJS">//create a generic javascript object.</span>
</pre>
<p>
Creates an object with the prototype <code>Object.prototype</code> that itself has a
null prototype. So the prototype chain for <code>objectRef</code> contains only one
object: <code>Object.prototype</code>. However:-
</p>
<pre>
<span class="commentJS">/* A "constructor" function for creating objects of a -
MyObject1 - type.
*/</span>
function MyObject1(formalParameter){
<span class="commentJS">/* Give the constructed object a property called - testNumber - and
assign it the value passed to the constructor as its first
argument:-
*/</span>
this.testNumber = formalParameter;
}
<span class="commentJS">/* A "constructor" function for creating objects of a -
MyObject2 - type:-
*/</span>
function MyObject2(formalParameter){
<span class="commentJS">/* Give the constructed object a property called - testString -
and assign it the value passed to the constructor as its first
argument:-
*/</span>
this.testString = formalParameter;
}
<span class="commentJS">/* The next operation replaces the default prototype associated with
all MyObject2 instances with an instance of MyObject1, passing the
argument - 8 - to the MyObject1 constructor so that its -
testNumber - property will be set to that value:-
*/</span>
MyObject2.prototype = new MyObject1( 8 );
<span class="commentJS">/* Finally, create an instance of - MyObject2 - and assign a reference
to that object to the variable - objectRef - passing a string as the
first argument for the constructor:-
*/</span>
var objectRef = new MyObject2( "String_Value" );
</pre>
<p>
The instance of <code>MyObject2</code> referred to by the <code>objectRef</code> variable has a
prototype chain. The first object in that chain is the instance of
<code>MyObject1</code> that was created and assigned to the prototype
property of the <code>MyObject2</code> constructor. The instance of
<code>MyObject1</code> has a prototype, the object that was assigned to the function
<code>MyObject1</code>'s prototype property by the implementation. That object has
a prototype, the default <code>Object</code> prototype that corresponds with the
object referred to by <code>Object.prototype</code>. <code>Object.prototype</code> has a null
prototype so the prototype chain comes to an end at this point.
</p>
<p>
When a property accessor attempts to read a named property form the
object referred to by the variable <code>objectRef</code> the whole
prototype chain can enter into the process. In the simple case:-
</p>
<pre>
var val = objectRef.testString;
</pre>
<p>
- the instance of <code>MyObject2</code> referred to by <code>objectRef</code> has
a property with the name "testString" so it is the value of
that property, set to "String_Value", that is assigned to the
variable <code>val</code>. However:-
</p>
<pre>
var val = objectRef.testNumber;
</pre>
<p>
- cannot read a named property form the instance of
<code>MyObject2</code> itself as it has no such property but the
variable <code>val</code> is set to the value of <code>8</code> rather
than undefined because having failed to find a corresponding named
property on the object itself the interpreter then examines the object
that is its prototype. Its prototype is the instance of
<code>MyObject1</code> and it was created with a property named
"testNumber" with the value <code>8</code> assigned to that property, so
the property accessor evaluates as the value <code>8</code>. Neither
<code>MyObject1</code> or <code>MyObject2</code> have defined a
<code>toString</code> method, but if a property accessor attempts to
read the value of a <code>toString</code> property from
<code>objectRef</code>:-
</p>
<pre>
var val = objectRef.toString;
</pre>
<p>
- the <code>val</code> variable is assigned a reference to a function.
That function is the <code>toString</code> property of
<code>Object.prototype</code> and is returned because the process of
examining the prototype of <code>objectRef</code>, when
<code>objectRef</code> turns out not to have a "toString"
property, is acting on an object, so when that prototype is found to
lack the property its prototype is examined in turn. Its prototype
is <code>Object.prototype</code>, which does have a
<code>toString</code> method so it is a reference to that function
object that is returned.
</p>
<p>
Finally:-
</p>
<pre>
var val = objectRef.madeUpProperty;
</pre>
<p>
- returns <code>undefined</code>, because as the process of working up the prototype
chain finds no properties on any of the object with the name
"madeUpPeoperty" it eventually gets to the prototype of
<code>Object.prototype</code>, which is null, and the process ends
returning <code>undefined</code>.
</p>
<p>
The reading of named properties returns the first value found, on the
object or then from its prototype chain. The assigning of a value to a
named property on an object will create a property on the object itself
if no corresponding property already exists.
</p>
<p>
This means that if a value was assigned as
<code>objectRef.testNumber = 3</code> a "testNumber" property
will be created on the instance of <code>MyObject2</code> itself, and
any subsequent attempts to read that value will retrieve that value as
set on the object. The prototype chain no longer needs to be examined
to resolve the property accessor, but the instance of
<code>MyObject1</code> with the value of <code>8</code> assigned to its
"testNumber" property is unaltered. The assignment to the
<code>objectRef</code> object masks the corresponding property in its
prototype chain.
</p>
<p>
Note: ECMAScript defines an internal <code>[[prototype]]</code>
property of the internal Object type. This property is not directly accessible with
scripts, but it is the chain of objects referred to with the
internal <code>[[prototype]]</code> property that is used in property
accessor resolution; the object's prototype chain. A public
<code>prototype</code> property exists to allow the assignment,
definition and manipulation of prototypes in association with the
internal <code>[[prototype]]</code> property. The details of the
relationship between to two are described in ECMA 262 (3rd edition)
and are beyond the <dfn>scope</dfn> of this discussion.
</p>
<h2 id="clIRExSc">Identifier Resolution, Execution Contexts and scope chains</h2>
<h3 id="clExCon">The Execution Context</h3>
<p>
An <dfn>execution context</dfn> is an abstract concept used by the ECMSScript
specification (ECMA 262 3rd edition) to define the behaviour required
of ECMAScript implementations. The specification does not say anything
about how <dfn>execution contexts</dfn> should be implemented but execution
contexts have associated attributes that refer to specification defined
structures so they might be conceived (and even implemented) as objects
with properties, though not public properties.
</p>
<p>
All javascript code is executed in an <dfn>execution context</dfn>. Global code
(code executed inline, normally as a JS file, or <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> page, loads) gets
executed in <dfn>global</dfn> <dfn>execution context</dfn>, and each invocation of a function (possibly as a constructor) has an associated
<dfn>execution context</dfn>. Code executed with the <code>eval</code> function
also gets a distinct execution context but as <code>eval</code> is
never normally used by javascript programmers it will not be discussed
here. The specified details of <dfn>execution contexts</dfn> are to be found in
section 10.2 of ECMA 262 (3rd edition).
</p>
<p>
When a javascript function is called it enters an <dfn>execution context</dfn>,
if another function is called (or the same function recursively) a new
<dfn>execution context</dfn> is created and execution enters that context for the
duration of the function call. Returning to the original execution
context when that called function returns. Thus running javascript code
forms a stack of <dfn>execution contexts</dfn>.
</p>
<p>
When an <dfn>execution context</dfn> is created a number of things happen in a
defined order. First, in the <dfn>execution context</dfn> of a function, an
"Activation" object is created. The activation object is
another specification mechanism. It can be considered as an object
because it ends up having accessible named properties, but it is not a
normal object as it has no prototype (at least not a defined prototype)
and it cannot be directly referenced by javascript code.
</p>
<p>
The next step in the creation of the <dfn>execution context</dfn> for a function
call is the creation of an <code>arguments</code> object, which is an
array-like object with integer indexed members corresponding with the
arguments passed to the function call, in order. It also has
<code>length</code> and <code>callee</code> properties (which are not
relevant to this discussion, see the spec for details). A property of
the Activation object is created with the name "arguments"
and a reference to the <code>arguments</code> object is assigned to
that property.
</p>
<p>
Next the <dfn>execution context</dfn> is assigned a <dfn>scope</dfn>. A <dfn>scope</dfn> consists of a
list (or chain) of objects. Each function object has an internal
<code>[[scope]]</code> property (which we will go into more detail
about shortly) that also consists of a list (or chain) of objects.
The <dfn>scope</dfn> that is assigned to the <dfn>execution context</dfn> of a function call
consists of the list referred to by the <code>[[scope]]</code> property
of the corresponding function object with the Activation object added
at the front of the chain (or the top of the list).
</p>
<p>
Then the process of "variable instantiation" takes place using an object
that ECMA 262 refers to as the "Variable" object. However,
the Activation object is used as the Variable object (note this, it is
important: they are the same object). Named properties of the Variable
object are created for each of the function's formal parameters, and if
arguments to the function call correspond with those parameters the
values of those arguments are assigned to the properties (otherwise the
assigned value is <code>undefined</code>). Inner function definitions
are used to create function objects which are assigned to properties of
the Variable object with names that correspond to the function name
used in the function declaration. The last stage of variable
instantiation is to create named properties of the Variable object
that correspond with all the local variables declared within the
function.
</p>
<p>
The properties created on the Variable object that correspond with
declared local variables are initially assigned <code>undefined</code>
values during variable instantiation, the actual initialisation of
local variables does not happen until the evaluation of the
corresponding assignment expressions during the execution of the
function body code.
</p>
<p>
It is the fact that the Activation object, with its
<code>arguments</code> property, and the Variable object, with named
properties corresponding with function local variables, are the same
object, that allows the identifier <code>arguments</code> to be treated
as if it was a function local variable.
</p>
<p>
Finally a value is assigned for use with the <code>this</code> keyword.
If the value assigned refers to an object then property accessors
prefixed with the <code>this</code> keyword reference properties of
that object. If the value assigned (internally) is null then the
<code>this</code> keyword will refer to the global object.
</p>
<p>
The global execution context gets some slightly different handling as
it does not have arguments so it does not need a defined Activation
object to refer to them. The global execution context does need a <dfn>scope</dfn>
and its <dfn>scope chain</dfn> consists of exactly one object, the global object.
The global execution context does go through variable instantiation,
its inner functions are the normal top level function declarations that
make up the bulk of javascript code. The global object is used as the
Variable object, which is why globally declared functions become
properties of the global object. As do globally declared variables.
</p>
<p>
The global execution context also uses a reference to the global object
for the <code>this</code> object.
</p>
<h3 id="clScCh">scope chains and [[scope]]</h3>
<p>
The <dfn>scope chain</dfn> of the execution context for a function call is
constructed by adding the execution context's Activation/Variable
object to the front of the <dfn>scope chain</dfn> held in the function
object's <code>[[scope]]</code> property, so it is important to
understand how the internal <code>[[scope]]</code> property is
defined.
</p>
<p>
In ECMAScript functions are objects, they are created during variable
instantiation from function declarations, during the evaluation of
function expressions or by invoking the <code>Function</code>
constructor.
</p>
<p>
Function objects created with the <code>Function</code> constructor
always have a <code>[[scope]]</code> property referring to a <dfn>scope
chain</dfn> that only contains the global object.
</p>
<p>
Function objects created with function declarations or function
expressions have the <dfn>scope chain</dfn> of the execution context in which
they are created assigned to their internal <code>[[scope]]</code>
property.
</p>
<p>
In the simplest case of a global function declaration such as:-
</p>
<pre>
function exampleFunction(formalParameter){
... <span class="commentJS">// function body code</span>
}
</pre>
<p>
- the corresponding function object is created during the variable
instantiation for the global execution context. The global execution
context has a <dfn>scope chain</dfn> consisting of only the global object. Thus
the function object that is created and referred to by the property of
the global object with the name "exampleFunction" is
assigned an internal <code>[[scope]]</code> property referring to a
<dfn>scope chain</dfn> containing only the global object.
</p>
<p>
A similar <dfn>scope chain</dfn> is assigned when a function expression is
executed in the global context:-
</p>
<pre>
var exampleFuncRef = function(){
... <span class="commentJS">// function body code</span>
}
</pre>
<p>
- except in this case a named property of the global object is created
during variable instantiation for the global execution context but the
function object is not created, and a reference to it assigned to the
named property of the global object, until the assignment expression is
evaluated. But the creation of the function object still happens in the
global execution context so the <code>[[scope]]</code> property of the
created function object still only contains the global object in the
assigned scope chain.
</p>
<p>
Inner function declarations and expressions result in function objects
being created within the execution context of a function so they get
more elaborate scope chains. Consider the following code, which defines
a function with an inner function declaration and then executes the
outer function:-
</p>
<pre>
function exampleOuterFunction(formalParameter){
function exampleInnerFuncitonDec(){
... <span class="commentJS">// inner function body</span>
}
... <span class="commentJS">// the rest of the outer function body.</span>
}
exampleOuterFunction( 5 );
</pre>
<p>
The function object corresponding with the outer function declaration
is created during variable instantiation in the global execution context
so its <code>[[scope]]</code> property contains the one item scope
chain with only the global object in it.
</p>
<p>
When the global code executes the call to the
<code>exampleOuterFunction</code> a new execution context is created for
that function call and an Activation/Variable object along with it.
The <dfn>scope</dfn> of that new execution context becomes the chain consisting of
the new Activation object followed by the chain refereed to by the
outer function object's <code>[[scope]]</code> property (just the
global object). Variable instantiation for that new execution context
results in the creation of a function object that corresponds with the
inner function definition and the <code>[[scope]]</code> property of
that function object is assigned the value of the <dfn>scope</dfn> from the
execution context in which it was created. A <dfn>scope chain</dfn> that contains
the Activation object followed by the global object.
</p>
<p>
So far this is all automatic and controlled by the structure and
execution of the source code. The <dfn>scope chain</dfn> of the execution context
defines the <code>[[scope]]</code> properties of the function objects
created and the <code>[[scope]]</code> properties of the function
objects define the <dfn>scope</dfn> for their execution contexts (along with the
corresponding Activation object). But ECMAScript provides the
<code>with</code> statement as a means of modifying the scope chain.
</p>
<p>
The <code>with</code> statement evaluates an expression and if that
expression is an object it is added to the <dfn>scope chain</dfn> of the current
execution context (in front of the Activation/Variable object). The
<code>with</code> statement then executes another statement (that may
itself be a block statement) and then restores the execution context's
<dfn>scope chain</dfn>to what it was before.
</p>
<p>
A function declaration could not be affected by a <code>with</code>
statement as they result in the creation of function objects during
variable instantiation, but a function expression can be evaluated
inside a <code>with</code> statement:-
</p>
<pre>
<span class="commentJS">/* create a global variable - y - that refers to an object:- */</span>
var y = {x:5}; <span class="commentJS">// object literal with an - x - property</span>
function exampleFuncWith(){
var z;
<span class="commentJS">/* Add the object referred to by the global variable - y - to the
front of he scope chain:-
*/</span>
with(y){
<span class="commentJS">/* evaluate a function expression to create a function object
and assign a reference to that function object to the local
variable - z - :-
*/</span>
z = function(){
... <span class="commentJS">// inner function expression body;</span>
}
}
...
}
<span class="commentJS">/* execute the - exampleFuncWith - function:- */</span>
exampleFuncWith();
</pre>
<p>
When the <code>exampleFuncWith</code> function is called the resulting
execution context has a <dfn>scope chain</dfn> consisting of its Activation object
followed by the global object. The execution of the <code>with</code>
statement adds the object referred to by the global variable
<code>y</code> to the front of that <dfn>scope chain</dfn> during the evaluation
of the function expression. The function object created by the
evaluation of the function expression is assigned a
<code>[[scope]]</code> property that corresponds with the <dfn>scope</dfn> of the
execution context in which it is created. A <dfn>scope chain</dfn> consisting of
object <code>y</code> followed by the Activation object from the
execution context of the outer function call, followed by the global
object.
</p>
<p>
When the block statement associated with the <code>with</code>
statement terminates the <dfn>scope</dfn> of the execution context is restored
(the <code>y</code> object is removed), but the function object has
been created at that point and its <code>[[scope]]</code> property
assigned a reference to a <dfn>scope chain</dfn> with the <code>y</code> object
at its head.
</p>
<h3><a name="clIdRes" id="clIdRes">Identifier Resolution</a></h3>
<p>
Identifiers are resolved against the scope chain. ECMA 262 categorises
<code>this</code> as a keyword rather than an identifier, which is not
unreasonable as it is always resolved dependent on the
<code>this</code> value in the execution context in which it is used,
without reference to the scope chain.
</p>
<p>
Identifier resolution starts with the first object in the scope chain.
It is checked to see if it has a property with a name that corresponds
with the identifier. Because the <dfn>scope chain</dfn> is a chain of objects
this checking encompasses the prototype chain of that object (if it
has one). If no corresponding value can be found on the first object
in the <dfn>scope chain</dfn> the search progresses to the next object. And so on until
one of the objects in the chain (or one of its prototypes) has a
property with a name that corresponds with the identifier or the scope
chain is exhausted.
</p>
<p>
The operation on the identifier happens in the same way as the use of
property accessors on objects described above. The object identified
in the <dfn>scope chain</dfn> as having the corresponding property takes the
place of the object in the property accessor and the identifier acts
as a property name for that object. The global object is always at the
end of the scope chain.
</p>
<p>
As execution contexts associated with function calls will have the
Activation/Variable object at the front of the chain, identifiers used
in function bodies are effectively first checked to see whether they
correspond with formal parameters, inner function declaration names or
local variables. Those would be resolved as named properties of the
Activation/Variable object.
</p>
<h2><a name="clClose" id="clClose">Closures</a></h2>
<h3><a name="clAtGb" id="clAtGb">Automatic Garbage Collection</a></h3>
<p>
ECMAScript uses automatic garbage collection. The specification
does not define the details, leaving that to the implementers to sort
out, and some implementations are known to give a very low priority to
their garbage collection operations. But the general idea is that if an
object becomes un-referable (by having no remaining references to it
left accessible to executing code) it becomes available for garbage
collection and will at some future point be destroyed and any resources
it is consuming freed and returned to the system for re-use.
</p>
<p>
This would normally be the case upon exiting an execution context. The
<dfn>scope chain</dfn> structure, the Activation/Variable object and any objects
created within the execution context, including function objects, would
no longer be accessible and so would become available for garbage
collection.
</p>
<h3><a name="clFrmC" id="clFrmC">Forming Closures</a></h3>
<p>
A closure is formed by returning a function object that was created
within an execution context of a function call from that function call
and assigning a reference to that inner function to a property of another
object. Or by directly assigning a reference to such a function object
to, for example, a global variable, a property of a globally accessible
object or an object passed by reference as an argument to the outer
function call. e.g:-
</p>
<pre>
function exampleClosureForm(arg1, arg2){
var localVar = 8;
function exampleReturned(innerArg){
return ((arg1 + arg2)/(innerArg + localVar));
}
<span class="commentJS">/* return a reference to the inner function defined as -
exampleReturned -:-
*/</span>
return exampleReturned;
}
var globalVar = exampleClosureForm(2, 4);
</pre>
<p>
Now the function object created within the execution context of the
call to <code>exampleClosureForm</code> cannot be garbage collected
because it is referred to by a global variable and is still accessible,
it can even be executed with <code>globalVar(n)</code>.
</p>
<p>
But something a little more complicated has happened because the
function object now referred to by <code>globalVar</code> was created
with a <code>[[scope]]</code> property referring to a scope chain
containing the Activation/Variable object belonging to the execution
context in which it was created (and the global object). Now the
Activation/Variable object cannot be garbage collected either as the
execution of the function object referred to by <code>globalVar</code>
will need to add the whole <dfn>scope chain</dfn> from its <code>[[scope]]</code>
property to the <dfn>scope</dfn> of the execution context created for each call to
it.
</p>
<p>
A closure is formed. The inner function object has the free variables
and the Activation/Variable object on the function's <dfn>scope chain</dfn> is
the environment that binds them.
</p>
<p>
The Activation/Variable object is trapped by being
referred to in the <dfn>scope chain</dfn> assigned to the internal
<code>[[scope]]</code> property of the function object now referred to
by the <code>globalVar</code> variable. The Activation/Variable object
is preserved along with its state; the values of its properties. Scope
resolution in the execution context of calls to the inner function will
resolve identifiers that correspond with named properties of that
Activation/Variable object as properties of that object. The value of
those properties can still be read and set even though the execution
context for which it was created has exited.
</p>
<p>
In the example above that Activation/Variable object has a state that
represents the values of formal parameters, inner function definitions
and local variables, at the time when the outer function returned
(exited its execution context). The <code>arg1</code> property has the
value <code>2</code>,the <code>arg2</code> property the value
<code>4</code>, <code>localVar</code> the value <code>8</code> and an
<code>exampleReturned</code> property that is a reference to the inner
function object that was returned form the outer function. (We will be
referring to this Activation/Variable object as "ActOuter1" in later
discussion, for convenience.)
</p>
<p>
If the <code>exampleClosureForm</code> function was called again as:-
</p>
<pre>
var secondGlobalVar = exampleClosureForm(12, 3);
</pre>
<p>
- a new execution context would be created, along with a new Activation
object. And a new function object would be returned, with its own
distinct <code>[[scope]]</code> property referring to a scope chain
containing the Activation object form this second execution context,
with <code>arg1</code> being <code>12</code> and <code>arg2</code>
being <code>3</code>. (We will be referring to this Activation/Variable
object as "ActOuter2" in later discussion, for convenience.)
</p>
<p>
A second and distinct closure has been formed by the second execution
of <code>exampleClosureForm</code>.
</p>
<p>
The two function objects created by the execution of
<code>exampleClosureForm</code> to which references have been assigned
to the global variable <code>globalVar</code> and
<code>secondGlobalVar</code> respectively, return the expression
<code>((arg1 + arg2)/(innerArg + localVar))</code>. Which applies
various operators to four identifiers. How these identifiers are
resolved is critical to the use and value of closures.
</p>
<p>
Consider the execution of the function object referred to by
<code>globalVar</code>, as <code>globalVar(2)</code>. A new execution
context is created and an Activation object (we will call it
"ActInner1"), which is added to the head of the scope chain
referred to the <code>[[scope]]</code> property of the executed
function object. ActInner1 is given a property named
<code>innerArg</code>, after its formal parameter and the argument
value <code>2</code> assigned to it. The <dfn>scope chain</dfn> for this new
execution context is: <span class="scopeCh">ActInner1-></span>
<span class="scopeCh">ActOuter1-></span>
<span class="scopeCh">global object</span>.
</p>
<p>
Identifier resolution is done against the <dfn>scope chain</dfn> so in order
to return the value of the expression
<code>((arg1 + arg2)/(innerArg + localVar))</code> the values of the
identifiers will be determined by looking for properties, with names
corresponding with the identifiers, on each object in the scope chain
in turn.
</p>
<p>
The first object in the chain is ActInner1 and it has a property named
<code>innerArg</code> with the value <code>2</code>. All of the other
3 identifiers correspond with named properties of ActOuter1;
<code>arg1</code> is <code>2</code>, <code>arg2</code> is
<code>4</code> and <code>localVar</code> is <code>8</code>. The
function call returns <code>((2 + 4)/(2 + 8))</code>.
</p>
<p>
Compare that with the execution of the otherwise identical function
object referred to by <code>secondGlobalVar</code>, as
<code>secondGlobalVar(5)</code>. Calling the Activation object for
this new execution context "ActInner2", the scope chain
becomes: <span class="scopeCh">ActInner2-></span>
<span class="scopeCh">ActOuter2-></span>
<span class="scopeCh">global object</span>. ActInner2 returns
<code>innerArg</code> as <code>5</code> and ActOuter2 returns
<code>arg1</code>, <code>arg2</code> and <code>localVar</code> as
<code>12</code>, <code>3</code> and <code>8</code> respectively. The
value returned is <code>((12 + 3)/(5 + 8))</code>.
</p>
<p>
Execute <code>secondGlobalVar</code> again and a new Activation object
will appear at the front of the <dfn>scope chain</dfn> but ActOuter2 will still
be next object in the chain and the value of its named properties will
again be used in the resolution of the identifiers <code>arg1</code>,
<code>arg2</code> and <code>localVar</code>.
</p>
<p>
This is how ECMAScript inner functions gain, and maintain, access to the formal
parameters, declared inner functions and local variables of the
execution context in which they were created. And it is how the
forming of a closure allows such a function object to keep referring
to those values, reading and writing to them, for as long as it
continues to exist. The Activation/Variable object from the execution
context in which the inner function was created remains on the scope
chain referred to by the function object's <code>[[scope]]</code>
property, until all references to the inner function are freed and
the function object is made available for garbage collection (along
with any now unneeded objects on its scope chain).
</p>
<p>
Inner function may themselves have inner functions, and the inner
functions returned from the execution of functions to form closures
may themselves return inner functions and form closures of their own.
With each nesting the <dfn>scope chain</dfn> gains extra Activation objects
originating with the execution contexts in which the inner function
objects were created. The ECMAScript specification requires a scope
chain to be finite, but imposes no limits on their length.
Implementations probably do impose some practical limitation but no
specific magnitude has yet been reported. The potential for nesting
inner functions seems so far to have exceeded anyone's desire to
code them.
</p>
<h2><a name="clClDo" id="clClDo">What can be done with Closures?</a></h2>
<p>
Strangely the answer to that appears to be anything and everything.
I am told that closures enable ECMAScript to emulate anything, so the
limitation is the ability to conceive and implement the emulation. That
is a bit esoteric and it is probably better to start with something a
little more practical.
</p>
<h3><a name="clSto" id="clSto">Example 1: setTimeout with Function References</a></h3>
<p>
A common use for a closure is to provide parameters for the execution
of a function prior to the execution of that function. For example,
when a function is to be provided as the first argument to the
<code>setTimout</code> function that is common in web browser
environments.
</p>
<p>
<code>setTimeout</code> schedules the execution of a function (or a
string of javascript source code, but not in this context), provided as
its first argument, after an interval expressed in milliseconds (as its
second argument). If a piece of code wants to use
<code>setTimeout</code> it calls the <code>setTimeout</code> function
and passes a reference to a function object as the first argument and
the millisecond interval as the second, but a reference to a function
object cannot provide parameters for the scheduled execution of that
function.
</p>
<p>
However, code could call another function that returned a reference to
an inner function object, with that inner function object being passed
by reference to the <code>setTimeout</code> function. The parameters to
be used for the execution of the inner function are passed with the
call to the function that returns it. <code>setTimout</code> executes
the inner function without passing arguments but that inner function
can still access the parameters provided by the call to the outer
function that returned it:-
</p>
<pre>
function callLater(paramA, paramB, paramC){
<span class="commentJS">/* Return a reference to an anonymous inner function created
with a function expression:-
*/</span>
return (function(){
<span class="commentJS">/* This inner function is to be executed with - setTimeout
- and when it is executed it can read, and act upon, the
parameters passed to the outer function:-
*/</span>