Scope & Closures
"this"
Presenter: Yauheni Pozdnyakov
t.me/youhy

We'll talk about...
-
Scope and closures
Compiler, lexical scope, functions, hoisting -
This or That?
Binding
Compiler view
JS is compiled language!
It is not compiled in advance, as C++, nor are the results of compilation portable among various distributed systems as Java or C# do
Compilation steps:
-
Tokenizing/Lexing
var a = 2 should be presented as var, a, =, 2 and ; - Parsing (Abstract Syntax Tree)
- Code-Generation
Any snippet of JavaScript has to be compiled before (usually right before!) it's executed
Scope: the entry point
-
Engine
Start-to-finish compilation and execution of JavaScript code -
Compiler
Handles code files parsing and code-generation -
Scope
holds a lookup list of the declared identifiers, enforces a strict set of rules of how these are accessible to currently executing code.
Scope: the entry point
var a = 2;
Compiler:
- Gets var a
- Checks scope if a is presented there
- If so, no need to declare it
- If not, scope should allocate the variable first
Declare a new variable called a for that scope collection - Pass code to Engine for later execution (a = 2)
Engine:
- Gets the code to handle
- Perform a scope lookup if a is accessible
- If so, use this variable
- If not, look for it through the upper level
Left and Right hand lookup
Side??? What side???
Of an assignment operation!
RHS look-up - a look-up of the value of some variable, like "go get the value of.." (who's the source of the assignment )
LHS look-up is trying to find the variable container itself, so that it can assign (who's the target of the assignment)
console.log( a ); //RHS
var a = 2;//LHS
function foo(a) {
console.log( a ); // 2
}
foo( 2 );
- foo(..) - RHS
- Hidden a = 2, so LHS
- console.log(a) // 2 RHS
Left and Right hand lookup
function foo(a) {
var b = a;
return a + b;
}
var c = foo( 2 );
3 - LHS look-ups
4 - RHS look-ups
LHS:
c =...
a = 2
b = ..
RHS:
foo(2..
= a;
a + ..
.. + b
Nested Scope
function foo(a) {
console.log( a + b );
}
var b = 2;
foo( 2 ); // 4
RHS reference for b cannot be resolved inside the function foo!
What happens?
- Check the foo Scope for b with RHS
- No b :((
- Check the outer Scope for b with RHS
- Ha-Ha b is there!!!

Where do ReferenceError and TypeError come from?
function foo(a) {
console.log( a + b );
b = a;
}
foo( 2 );
function foo(a) {
b = a;
console.log( a + b );
}
foo( 2 );
ReferenceError: b is not defined
4
- RHS lookup for b the first time
- b is not found
- results in a ReferenceError
- LHS lookup for b the first time
- comes to the top of the Scope
- creates new one in the global Scope
RHS lookup - succeeded! But you're trying to perform something impossible - TypeError
Conclusion
- Scope is the set of rules that determines where and how a variable (identifier) can be looked-up.
- The JavaScript Engine first compiles code before it executes
- Both LHS and RHS reference look-ups start at the currently executing Scope
- ReferenceError is Scope resolution-failure related, but TypeError shows that Scope resolution was successful, but there was an attempt to perform an illegal action against the result.
Lexical Scope
lexical scope is scope that is defined at lexing time

Block and Function Scope
function foo(a) {
var b = 2;
// some code
function bar() {
// ...
}
// some more code
var c = 3;
}
bar(); // fails
console.log( a, b, c ); // also fails
Block and Function Scope
var a = 2;
function foo() {
var a = 3;
console.log( a );
}
foo();
console.log( a );
// 2
var a = 2;
(function IIFE(){
var a = 3;
console.log( a );
})();
console.log( a );
// 3
// 2
var a = 2;
(function IIFE( global ){
var a = 3;
console.log( a );
console.log( global.a );
})( window );
console.log( a );
// 3
// 2
// 2
IFFE: Immediately Invoked Function Expression
Hoisting
a = 2;
var a;
console.log( a );
//2
var a;
a = 2;
console.log( a );
console.log( a );
var a = 2;
//undefined
var a; //undefined
console.log( a );
a = 2;
foo();
function foo() {
console.log( a ); // undefined
var a = 2;
}
foo(); // not ReferenceError, but TypeError!
var foo = function bar() {
// ...
};
var foo; //undefined
foo(); // not ReferenceError, but TypeError!
foo = function bar() {
// ...
};
Functions Hoist First
foo(); // 1
var foo;
function foo() {
console.log( 1 );
}
foo = function() {
console.log( 2 );
};
function foo() {
console.log( 1 );
}
foo(); // 1
foo = function() {
console.log( 2 );
};
foo(); // 3
function foo() {
console.log( 1 );
}
var foo = function() {
console.log( 2 );
};
function foo() {
console.log( 3 );
}
Closures
Closure is all around you in JavaScript, you just have to recognize it
function foo() {
var a = 2;
function bar() {
console.log( a );
}
return bar;
}
var baz = foo();
baz();
// 2
bar() still has a reference to that scope, and that reference is called closure.
Closure lets the function continue to access the lexical scope it was defined in at author-time.
Closures
var fn;
function foo() {
var a = 2;
function baz() {
console.log( a );
}
fn = baz; // assign `baz` to global variable
}
function bar() {
fn(); // look ma, I saw closure!
}
foo();
bar(); // 2
Closures
function CoolModule() {
var something = "cool";
var another = [1, 2, 3];
function doSomething() {
console.log( something );
}
function doAnother() {
console.log( another.join( " ! " ) );
}
return {
doSomething: doSomething,
doAnother: doAnother
};
}
var foo = CoolModule();
foo.doSomething(); // cool
foo.doAnother(); // 1 ! 2 ! 3
This or That
This is contextual based on the conditions of the function's invocation
Depends on the manner in which the function is called
When a function is invoked, an activation record (execution context) is created. It contains information about where the function was called from (the call-stack), how the function was invoked, what parameters were passed, etc.
This call side
function baz() {
console.log( "baz" );
bar();
}
function bar() {
console.log( "bar" );
foo();
}
function foo() {
console.log( "foo" );
}
baz();
// call-stack is: `baz`
// so, our call-site is in the global scope
// <-- call-site for `bar`
// call-stack is: `baz` -> `bar`
// so, our call-site is in `baz`
// <-- call-site for `foo`
// call-stack is: `baz` -> `bar` -> `foo`
// so, our call-site is in `bar`
// <-- call-site for `baz`
This binding
function foo() {
console.log( this.a );
}
var a = 2;
foo(); // 2
default binding for this applies to the function call
function foo() {
console.log( this.a );
}
var obj = {
a: 2,
foo: foo
};
var bar = obj.foo; // function reference
var a = "oops, global"; // `a` also property on global object
bar(); // "oops, global"
un-decorated call, the default binding applies
Explicit Binding
bind(..), call(..) and apply(..) methods
function foo() {
console.log( this.a );
}
var obj = {
a: 2
};
foo.call( obj ); // 2
From point of this binding, call(..) and apply(..) are identical. They do behave differently with their additional parameters.
function foo(something) {
console.log( this.a, something );
return this.a + something;
}
var obj = {
a: 2
};
var bar = foo.bind( obj );
var b = bar( 3 ); // 2 3
console.log( b ); // 5
bind(..) returns a new function that is hard-coded to call the original function with the this context set as you specified.
How to determine this?
-
Is the function called with new (new binding)? If so, this is the newly constructed object.
var bar = new foo()
-
Is the function called with call or apply (explicit binding), even hidden inside a bind hard binding? If so, this is the explicitly specified object.
var bar = foo.call( obj2 )
-
Is the function called with a context (implicit binding), otherwise known as an owning or containing object? If so, this is that context object.
var bar = obj1.foo()
-
Otherwise, default the this (default binding). If in strict mode, pick undefined, otherwise pick the globalobject.
var bar = foo()
Conclusion
-
Called with new? Use the newly constructed object.
-
Called with call or apply (or bind)? Use the specified object.
-
Called with a context object owning the call? Use that context object.
-
Default: undefined in strict mode, global object otherwise.
Determining the this binding for an executing function requires finding the direct call-site of that function.
Any questions?
THANK YOU FOR ATTENTION!!!
Scope & Closures
By Yauheni Pozdnyakov
Scope & Closures
- 130