3. A few definitions
Scope of a variable
Where is the variable accessible?
function foo() {
var x;
}
foo() is direct scope of x.
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 3 / 32
4. A few definitions
Static versus dynamic
Adjectives for describing phenomena in programming languages:
Static: pertaining to the source code
⇒ The scope of a variable is static
function f() {
var x = 3;
... // no effect on scope of x
}
⇒ Variables in JavaScript are statically scoped (or lexically scoped)
Dynamic: at runtime
⇒ function calls are dynamic
function g() { }
function f() { g() }
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 4 / 32
5. A few definitions
var declarations are function-scoped
foo is accessible in all of main():
function main() {
{ // block starts
var foo = 4;
} // block ends
console.log(foo); // 4
}
ECMAScript 6: block-scoped variable declarations via let.
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 5 / 32
6. A few definitions
Nested scopes
Everything from outer scopes is accessible from inner scopes.
function foo(arg) {
function bar() {
console.log('arg: ' + arg);
}
bar();
}
console.log(foo('hello')); // arg: hello
Outer scope: foo()
Inner scope: bar()
arg is accessible in its direct scope foo() and the inner scope bar().
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 6 / 32
9. Environments
Dimensions of environments
Environments must support:
Fresh variables (local, parameters) per function call (dynamic
dimension).
Nested scopes (static dimension).
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 9 / 32
10. Environments
Dynamic dimension: calling functions
function fac(n) {
if (n <= 1) {
return 1;
}
return n * fac(n - 1);
}
For each invocation:
Allocate storage for parameters and local variables
Discard afterwards (usually)
Solution: stack of execution contexts (references to environments)
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 10 / 32
11. Environments
var foo = 'abc';
function fac(n) {
if (n <= 1) {
return 1;
}
return n * fac(n - 1);
}
// YOU ARE HERE
fac(2);
0
…fac
'abc'foo
Lexical environmentsExecution contexts
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 11 / 32
12. Environments
var foo = 'abc';
function fac(n) {
if (n <= 1) {
return 1;
}
return n * fac(n - 1);
}
fac(2);
1
0
…fac
'abc'foo
2n
Lexical environmentsExecution contexts
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 12 / 32
13. Environments
var foo = 'abc';
function fac(n) {
if (n <= 1) {
return 1;
}
return n * fac(n - 1);
}
fac(2);
2
1
0
…fac
'abc'foo
1n
Lexical environmentsExecution contexts
2n
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 13 / 32
14. Environments
Static (lexical) dimension: nested scopes
function f(x) {
var foo;
function g(y, z) {
var bar;
}
}
Environment: field outer points to
“surrounding” environment.
Search environment chain for
variables.
Function: property [[Scope]]
points to environment “in which”
function was created.
Function call: set up outer via
[[Scope]].
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 14 / 32
15. Environments
function f(x) {
var foo;
function g(y, z) {
var bar;
}
g(7, 1);
}
// YOU ARE HERE
f(2);
0 …f
Lexical environmentsExecution contexts
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 15 / 32
16. Environments
function f(x) {
var foo;
function g(y, z) {
var bar;
}
g(7, 1);
}
f(2);
1
0 …f
…g
undefinedfoo
2x
outer
Lexical environmentsExecution contexts
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 16 / 32
17. Environments
function f(x) {
var foo;
function g(y, z) {
var bar;
}
g(7, 1);
}
f(2);
2
1
0 …f
…g
undefinedfoo
2x
outer
Lexical environmentsExecution contexts
undefinedbar
1z
7y
outer
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 17 / 32
19. Closures
Closures: Functions Stay Connected to Their Birth Scopes
function createInc(startValue) {
return function (step) {
startValue += step;
return startValue;
};
}
# var inc = createInc(5);
# inc(1)
6
# inc(2)
8
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 19 / 32
20. Closures
What is a closure?
Closure = function + connection to birth scope
Via internal property [[Scope]] of functions
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 20 / 32
21. Closures
Example: closures
Step 1
function createInc(startValue) {
return function (step) {
startValue += step;
return startValue;
};
}
var inc = createInc(5);
0
undefinedinc
createInc
Lexical environmentsExecution contexts Functions
[[Scope]]
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 21 / 32
22. Closures
Step 2
function createInc(startValue) {
return function (step) {
startValue += step;
return startValue;
};
}
var inc = createInc(5);
1
0
undefinedinc
createInc
5startValue
outer
Lexical environmentsExecution contexts Functions
[[Scope]]
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 22 / 32
23. Closures
Step 3
function createInc(startValue) {
return function (step) {
startValue += step;
return startValue;
};
}
var inc = createInc(5);
0
inc
createInc
5startValue
outer
[[Scope]]
Lexical environmentsExecution contexts Functions
[[Scope]]
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 23 / 32
24. Closures
Step 4
function createInc(startValue) {
return function (step) {
startValue += step;
return startValue; }; }
var inc = createInc(5);
console.log(inc(1)); // 6
1
0
inc
createInc
5startValue
1step
outer
outer
[[Scope]]
Lexical environmentsExecution contexts Functions
[[Scope]]
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 24 / 32
25. Closures
Step 5
function createInc(startValue) {
return function (step) {
startValue += step;
return startValue;
};
}
var inc = createInc(5);
console.log(inc(1)); // 6
0
inc
createInc
5startValue
outer
[[Scope]]
Lexical environmentsExecution contexts Functions
[[Scope]]
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 25 / 32
28. Bonus: inadvertent sharing
Wrong: all functions share the same i
function f() {
var result = [];
for (var i=0; i<3; i++) {
var func = function () {
return i;
};
result.push(func);
}
return result;
}
console.log(f()[1]()); // 3
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 28 / 32
29. Bonus: inadvertent sharing
Right: one environment per function, with snapshot of i
function f() {
var result = [];
for (var i=0; i<3; i++) {
(function () { // step 1: IIFE
var pos = i; // step 2: copy
var func = function () {
return pos;
};
result.push(func);
}());
}
return result;
}
console.log(f()[1]()); // 1
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 29 / 32