Post on 20-Oct-2014
description
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 endsconsole.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 variablesDiscard 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 HEREfac(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);
10
…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);
210
…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 forvariables.
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 HEREf(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);
10 …f
…gundefinedfoo
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);
210 …f
…gundefinedfoo
2x
outer
Lexical environmentsExecution contexts
undefinedbar1z7y
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: closuresStep 1
function createInc(startValue) {return function (step) {
startValue += step;return startValue;
};}var inc = createInc(5);
0undefinedinc
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);
10
undefinedinccreateInc
5startValueouter
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);
0inccreateInc
5startValueouter
[[Scope]]
Lexical environmentsExecution contexts Functions
[[Scope]]
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 23 / 32
Closures
Step 4function createInc(startValue) {
return function (step) {startValue += step;return startValue; }; }
var inc = createInc(5);console.log(inc(1)); // 6
10
inccreateInc
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
0inccreateInc
5startValueouter
[[Scope]]
Lexical environmentsExecution contexts Functions
[[Scope]]
Dr. Axel Rauschmayer (2ality.com) JavaScript’s variables 2014-03-30 25 / 32
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: IIFEvar pos = i; // step 2: copyvar 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 1function myFunction(myParam) {
var myVar = 123;return myFloat;
}var myFloat = 1.3;// Step 1myFunction('abc'); // Step 2
01.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 2function myFunction(myParam) {
var myVar = 123;return myFloat;
}var myFloat = 1.3;// Step 1myFunction('abc'); // Step 2
[[Scope]]10
1.3myFloatmyFunction
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