Scope in Javascript is an area where a variable has access to some value.

And there are 2 types of scope: Global scope and local scope.

Any variables defined in a function is called a local variable. They reside within the local scope of the function and blocks.

While variables defined outside of all functions and blocks are called global variables.

//index.js

//global variables
var total = 0;
var temp;


var sum = function (){
  //variable a and b are local variables 
  var a=10, b=25;
  return a+b;

}

if (total == 0) {
  //someNumber is a local variable in this block
  var someNumber = 42;
  total = someNumber;
}

Here are some rules we ought to know about scopes in Javascript.

A function has access to the values defined in the global scope

//global variables
var total = 0;


var sum = function (){
  var a=10, b=25;

  //we can use total, a global variable inside this function
  total = a+b;
  return total; // => 35

}

However, a function's local scope variables are not available anywhere outside that function.

Which means any variables defined in the child function is not available to the parent function or functions from the global scope.

//global variables

var total = a+b; // will return error as a and b are not accessible here.


var sum = function (){
  
  var a=10, b=25;

  return a+b;

}

A function has access to its own local scope variables

var whatIsThis;

var fn = function(){
  var name = "hello";
  whatIsThis = name; // have access to name
}
fn();
console.log(whatIsThis); // => "hello"

Pretty straight forward here. If a variable is defined in a function, it can be used anywhere in the function as long as it's declared beforehand.

A function has access to the values defined in the parent function

var whatIsThis;

var fn = function(){
  var name= "hello";
  var shout = function(){
	whatIsThis = name; // have access to name defined in the parent function.
	}
}
fn();
console.log(whatIsThis); // => "hello"

Over here, since name is not defined in shout() function. The compiler will look in the higher scope, which is fn() and can use the name variable defined there.

Inputs to a function are treated as local scope variables

var whatIsThis;

var fn = function(name){
  whatIsThis = name; // has access to name passed as a variable to fn()
}
fn("hello");

console.log(whatIsThis); // => "hello"

Also pretty straight forward. If you pass a variable to a function, that variable is accessible to the function.

Block scope can be created with let

var whatIsThis;

var fn = function(){
  var where = "outer";
  {
    let where = "inner";
  }
  whatIsThis = where; // is it inner or outer?
}
fn();

console.log(whatIsThis); // => "hello"

In this scenario, let where = "inner"; is created in its separate local scope by let. So it is not accessible by whatIsThis which is in the outer scope.

Note: { var where ="inner"; } would not work create a local scope and will be assigned to whatIsThis if used.

A function's local scope variables are not available anywhere outside that function

var whatIsThis;

var firstFn = function(){
	var firstVariable = "here";

	secondFn();
}

var secondFn = function() {
	whatIsThis = firstVariable; // has no access to firstVariable.
}

firstFn();

This code will not compile because firstVariable inside secondFn() is not defined. This is not the same as local scope variable reaching up to the parent scope.

If a variable defined in outer and inner scope share the same name, and the name is referenced in the inner scope, the inner variable will be referenced

var whatIsThis;

var sameName = "outer";

var fn = function(){
  var sameName = "inner";
  whatIsThis = sameName;
}

console.log(whatIsThis); => "inner"

Here sameName is defined in the outer and inner scope. But since whatIsThis is called in the inner scope (inside fn()). The inner sameName is referenced instead.

If a variable defined in outer and inner scope share the same name, and the name is referenced in the outer scope, the outer variable will be referenced

var whatIsThis;

var sameName = "outer";

var fn = function(){
  var sameName = "inner";
}
whatIsThis = sameName;

console.log(whatIsThis); => "outer"

Similar to the previous example, except that whatIsThis is referenced outside of fn(). So the outer sameName is referenced instead.

A new local scope is created every time a function is called

var whatIsThis;

var fn = function(){
  var counter = 10;
  counter = counter + 1;
  whatIsThis = counter; 
}

fn(); //whatIsThis = 11
fn(); //whatIsThis = ?

The answer is 11.

Whenever you call a function, a new function scope is created. This is also known as execution context.

Every time fn() is called, a new var counter = 10 is initialized. So even though the same function has been called before, the previous counter won't be retained.

Modifying a variable in the outer scope from an inner function has a lasting effect.


var counter = 10;

var fn = function(){
	counter = outerCounter +1;
}

fn(); counter = 11
fn(); counter = ??

The answer is 12. The difference between this and the previous example is that the counter is now defined outside of the function (outer scope).  

When we call fn() and increment counter, the result of this will be carried forward to the next fn() call since it's still within the same execution context and the scope hasn't been reset.