javascript

Javascript – Scope & Closures

cover.jpg

 

let’s talk about one of the most important topics in JS which is scope.

where do variables *live*? In other words, where are they stored? And, most importantly, how does our program find them when it needs them?

well-defined set of rules for storing variables in some location, and for finding those variables at a later time. We’ll call that set of rules: Scope.

1. Engine: responsible for start-to-finish compilation and execution of our JavaScript program.

2. Compiler: one of  Engine’s friends; handles all the dirty work of parsing and code-generation

3. Scope: another friend of  Engine; collects and maintains a look-up list of all the declared identifiers (variables), and enforces a strict set of rules as to how these are accessible to currently executing code.


When you see the program `var a = 2;`, you most likely think of that as one statement. But that’s not how our new friend *Engine* sees it. In fact, *Engine* sees two distinct statements, one which *Compiler* will handle during compilation, and one which *Engine* will handle during execution.

So, let’s break down how *Engine* and friends will approach the program `var a = 2;`.

The first thing *Compiler* will do with this program is perform lexing to break it down into tokens, which it will then parse into a tree. But when *Compiler* gets to code-generation, it will treat this program somewhat differently than perhaps assumed.

A reasonable assumption would be that *Compiler* will produce code that could be summed up by this pseudo-code: “Allocate memory for a variable, label it `a`, then stick the value `2` into that variable.” Unfortunately, that’s not quite accurate.

*Compiler* will instead proceed as:

1. Encountering `var a`, *Compiler* asks *Scope* to see if a variable `a` already exists for that particular scope collection. If so, *Compiler* ignores this declaration and moves on. Otherwise, *Compiler* asks *Scope* to declare a new variable called `a` for that scope collection.

2. *Compiler* then produces code for *Engine* to later execute, to handle the `a = 2` assignment. The code *Engine* runs will first ask *Scope* if there is a variable called `a` accessible in the current scope collection. If so, *Engine* uses that variable. If not, *Engine* looks *elsewhere* (see nested *Scope* section below).

If *Engine* eventually finds a variable, it assigns the value `2` to it. If not, *Engine* will raise its hand and yell out an error!

To summarize: two distinct actions are taken for a variable assignment: First, *Compiler* declares a variable (if not previously declared in the current scope), and second, when executing, *Engine* looks up the variable in *Scope* and assigns to it, if found.


Capture.PNG

1. Identify all the LHS look-ups (there are 3!).

**`c = ..`   ,    `a = 2` (implicit param assignment)   and   `b = ..`**

2. Identify all the RHS look-ups (there are 4!).

**`foo(2..`,   `= a;`   , `a + ..` and `.. + b`**


We said that *Scope* is a set of rules for looking up variables by their identifier name. There’s usually more than one *Scope* to consider, however.

Just as a block or function is nested inside another block or function, scopes are nested inside other scopes. So, if a variable cannot be found in the immediate scope, *Engine* consults the next outer containing scope, continuing until found or until the outermost (aka, global) scope has been reached.

function foo(a) {
  console.log( a + b );
}
var b = 2;
foo ( 2 );  // 4

The RHS reference for `b` cannot be resolved inside the function `foo`, but it can be resolved in the *Scope* surrounding it (in this case, the global).

fig1.png

The building represents our program’s nested *Scope* rule set. The first floor of the building represents your currently executing *Scope*, wherever you are. The top level of the building is the global *Scope*.

function foo(a) {
  console.log( a + b );   // ReferenceError
  b = a;
}
foo ( 2 );

When the RHS look-up occurs for `b` the first time, it will not be found. This is said to be an “undeclared” variable, because it is not found in the scope.

If an RHS look-up fails to ever find a variable, anywhere in the nested *Scope*s, this results in a `ReferenceError` being thrown by the *Engine*. It’s important to note that the error is of the type `ReferenceError`.

By contrast, if the *Engine* is performing an LHS look-up and arrives at the top floor (global *Scope*) without finding it, and if the program is not running in “Strict Mode”, then the global *Scope* will create a new variable of that name **in the global scope**, and hand it back to *Engine*.

*”No, there wasn’t one before, but I was helpful and created one for you.”*

Strict Mode“, which was added in ES5, has a number of different behaviors from normal/relaxed/lazy mode. One such behavior is that it disallows the automatic/implicit global variable creation. In that case, there would be no global *Scope*’d variable to hand back from an LHS look-up, and *Engine* would throw a `ReferenceError` similarly to the RHS case.

Now, if a variable is found for an RHS look-up, but you try to do something with its value that is impossible, such as trying to execute-as-function a non-function value, or reference a property on a `null` or `undefined` value, then *Engine* throws a different kind of error, called a TypeError.

`ReferenceError` is *Scope* resolution-failure related, whereas `TypeError`  implies that *Scope* resolution was successful, but that there was an illegal/impossible action attempted against the result.


Review :

Scope is the set of rules that determines where and how a variable (identifier) can be looked-up. This look-up may be for the purposes of assigning to the variable, which is an LHS (left-hand-side) reference, or it may be for the purposes of retrieving its value, which is an RHS (right-hand-side) reference.

The JavaScript *Engine* first compiles code before it executes, and in so doing, it splits up statements like `var a = 2;` into two separate steps:

1. First, `var a` to declare it in that *Scope*. This is performed at the beginning, before code execution.

2. Later, `a = 2` to look up the variable (LHS reference) and assign to it if found.

Both LHS and RHS reference look-ups start at the currently executing *Scope*, and if need be (that is, they don’t find what they’re looking for there), they work their way up the nested *Scope*, one scope (floor) at a time, looking for the identifier, until they get to the global (top floor) and stop, and either find it, or don’t.

Unfulfilled RHS references result in `ReferenceError`s being thrown. Unfulfilled LHS references result in an automatic, implicitly-created global of that name (if not in “Strict Mode” , or a `ReferenceError` (if in “Strict Mode”).


fig2.png

There are three nested scopes inherent in this code example. It may be helpful to think about these scopes as bubbles inside of each other.

**Bubble 1** encompasses the global scope, and has just one identifier in it: `foo`.

**Bubble 2** encompasses the scope of `foo`, which includes the three identifiers: `a`, `bar` and `b`.

**Bubble 3** encompasses the scope of `bar`, and it includes just one identifier: `c`.

what exactly makes a new bubble? Is it only the function? Can other structures in JavaScript create bubbles of scope?

each function you declare creates a bubble for itself, but no other structures create their own scope bubbles. this is not quite true.

The traditional way of thinking about functions is that you declare a function, and then add code inside it. But the inverse thinking is equally powerful and useful: take any arbitrary section of code you’ve written, and wrap a function declaration around it, which in effect “hides” the code.

function doSomething(a) {
   b = a + doSomethingElse( a * 2 );
   console.log( b * 3 );
}
function doSomethingElse(a) {
   return a - 1;
}
var b;
doSomething( 2 ); // 15

In this snippet, the b variable and the doSomethingElse(..) function are likely “private” details of how doSomething(..) does its job. Giving the enclosing scope “access” to b and doSomethingElse(..) is not only unnecessary but also possibly “dangerous”, in that they may be used in unexpected ways, intentionally or not, and this may violate pre-condition assumptions of doSomething(..).

A more “proper” design would hide these private details inside the scope of doSomething(..), such as:

function doSomething(a) {
   function doSomethingElse(a) {
      return a - 1;
   }
 var b;
 b = a + doSomethingElse( a * 2 );
 console.log( b * 3 );
}
doSomething( 2 ); // 15

Now, b and doSomethingElse(..) are not accessible to any outside influence, instead controlled only by doSomething(..). The functionality and end-result has not been affected, but the design keeps private details private, which is usually considered better software.

What is block scope?

A programming language has block scope if a variable declared inside some block of code enclosed by curly braces is only visible within that block of code, and that variable is not visible outside of that particular block of code.

Think of a “block” of code as an an if statement, for loop, while loop, etc.

Javascript does not have block scope.

function scopeTest() {
  for (var i = 0; i <= 5; i++) {
    var inFor = i; 
  }
alert(inFor);
}
scopeTest( ); // retrun 5

So Javascript doesn’t use block scope,but it uses  function scope.


 var a;
 console.log (a);  // output: undefined
a = 2; 
var a;
console.log (a);  // output: 2
console.log (a);  // output: undefined
var a = 2;

this’s little confused we need to know something about the compilers. Recall that the *Engine* actually will compile your JavaScript code before it interprets it. Part of the compilation phase was to find and associate all declarations with their appropriate scopes. So, the best way to think about things is that all declarations, both variables and functions, are processed first, before any part of your code is executed.

When you see var a = 2; , you probably think of that as one statement. But JavaScript actually thinks of it as two statements: var a; and a = 2;. The first statement, the declaration, is processed during the compilation phase. The second statement, the assignment, is left **in place** for the execution phase.

So, one way of thinking, sort of metaphorically, about this process, is that variable and function declarations are “moved” from where they appear in the flow of the code to the top of the code. This gives rise to the name “Hoisting“.

foo();                             |  function foo() {
function foo() {                   |    var a;
    console.log( a ); // undefined |    console.log (a); //  undefined
    var a = 2;                     |    a = 2;
}                                  |  }
                                   |  foo();

Function declarations are hoisted, as we just saw. But function expressions are not.

foo(); //---- Not ReferenceError, but TypeError!
var foo = function bar() {
 // ...
};

The variable identifier foo is hoisted and attached to the enclosing scope (global) of this program, so foo() doesn’t fail as a `ReferenceError`. But foo has no value yet (as it would if it had been a true function declaration instead of expression). So, foo() is attempting to invoke the `undefined` value, which is a `TypeError` illegal operation.

foo();    // TypeError
bar();    // ReferenceError
var foo = function bar() {
   // ...
}
var foo;

foo(); // TypeError
bar(); // ReferenceError

foo = function() {
 var bar = ...self...
 // ...
}

functions are hoisted first, and then variables.


Closure

function foo() {
  var a = 2;
    function bar() {    // -- has a closure over the foo's scope
    console.log( a ); // 2
  }
 bar();
}
foo();

 so what’s closure ? – From a purely academic perspective, what is said of the above snippet is that the function bar() has a *closure* over the scope of foo() (and indeed, even over the rest of the scopes it has access to, such as the global scope in our case). Put slightly differently, it’s said that bar() closes over the scope of foo(). Why? Because bar() appears nested inside of foo(). Plain and simple.

function sayHello2(name) {
  var text = 'Hello ' + name; // Local variable
  var say = function() { console.log(text); }
  return say;
}
var say2 = sayHello2('Bob');
say2(); // logs "Hello Bob"

The above code has a closure because the anonymous function function() { console.log(text); } is declared inside another function, sayHello2() in this example. In JavaScript, if you use the function keyword inside another function, you are creating a closure

In C and most other common languages, after a function returns, all the local variables are no longer accessible because the stack-frame is destroyed.

In JavaScript, if you declare a function within another function, then the local variables can remain accessible after returning from the function you called. This is demonstrated above, because we call the function say2() after we have returned from sayHello2(). Notice that the code that we call references the variable text, which was a local variable of the function sayHello2().

function() { console.log(text); } // Output of say2.toString();

Looking at the output of say2.toString(), we can see that the code refers to the variable text. The anonymous function can reference text which holds the value 'Hello Bob' because the local variables of sayHello2() are kept in a closure.

function greeter(name, age) {
  var message = name + ", who is " + age + " years old, says hi!";

  return function greet() {
    console.log(message);
  };
}

// Generate the closure
var bobGreeter = greeter("Bob", 47);
// Use the closure
bobGreeter();

Note that the greet function is nested within the greeter function. This means it’s within the lexical scope of greeterand thus according to the rules of closure has access to the local variables of greeter including message, name, and age.

function Person (name){
 
 var name = name; // this is a provate variable
 this.getName = function (){
 return name; 
 };
}
var p = new Person("Ahmed");
console.log(p);

Capture.PNG

and another example

var add = (function (){
 var counter = 0;
 return function (){
 console.log( counter++);
 };
})();

add();  // 0
add();  // 1
add();  // 2
add();  // 3

That’s my notes about scope and closure from YDKJ Book and other resources, i hope this article be helpful to you guys.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s