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