JavaScript’s variables: scopes, environments, closures
Dr. Axel Rauschmayer
2ality.com
2014-03-30
CodeFest 2014
A few definitions
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
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
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
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
Environments
Environments
Environments: managing variables
Environments:
Data structure for storing variables
Maps from variable names to values
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 8 / 32
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
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
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
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
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
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
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
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
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
Closures
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
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
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
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
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
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
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
Thank you!
Free online: speakingjs.com
Bonus: inadvertent sharing
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
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
Bonus: example
Bonus: example
Example: environments
Step 1
function myFunction(myParam) {
var myVar = 123;
return myFloat;
}
var myFloat = 1.3;
// Step 1
myFunction('abc'); // Step 2
0
1.3myFloat
myFunction
Chain of environments
(lexical)
Stack of execution
contexts (dynamic)
[[Scope]]
function (myParam)
...
}
Functions
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 31 / 32
Bonus: example
Step 2
function myFunction(myParam) {
var myVar = 123;
return myFloat;
}
var myFloat = 1.3;
// Step 1
myFunction('abc'); // Step 2
[[Scope]]
1
0
1.3myFloat
myFunction
myVar 123
'abc'myParam
outer
function (myParam)
...
}
Chain of environments
(lexical)
Stack of execution
contexts (dynamic)
Functions
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 32 / 32

CodeFest 2014. Axel Rauschmayer — JavaScript’s variables: scopes, environments, closures

  • 1.
    JavaScript’s variables: scopes,environments, closures Dr. Axel Rauschmayer 2ality.com 2014-03-30 CodeFest 2014
  • 2.
  • 3.
    A few definitions Scopeof 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 Staticversus 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 vardeclarations 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 Nestedscopes 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
  • 7.
  • 8.
    Environments Environments: managing variables Environments: Datastructure for storing variables Maps from variable names to values Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 8 / 32
  • 9.
    Environments Dimensions of environments Environmentsmust 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: callingfunctions 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) { varfoo; 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) { varfoo; 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) { varfoo; 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
  • 18.
  • 19.
    Closures Closures: Functions StayConnected 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 aclosure? 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 functioncreateInc(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
  • 26.
  • 27.
  • 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
  • 30.
  • 31.
    Bonus: example Example: environments Step1 function myFunction(myParam) { var myVar = 123; return myFloat; } var myFloat = 1.3; // Step 1 myFunction('abc'); // Step 2 0 1.3myFloat myFunction Chain of environments (lexical) Stack of execution contexts (dynamic) [[Scope]] function (myParam) ... } Functions Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 31 / 32
  • 32.
    Bonus: example Step 2 functionmyFunction(myParam) { var myVar = 123; return myFloat; } var myFloat = 1.3; // Step 1 myFunction('abc'); // Step 2 [[Scope]] 1 0 1.3myFloat myFunction myVar 123 'abc'myParam outer function (myParam) ... } Chain of environments (lexical) Stack of execution contexts (dynamic) Functions Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 32 / 32