DEV Community

Tejeswararao123
Tejeswararao123

Posted on

Scope, Hoisting and Closures in Javascript

Scope

Scope in JavaScript refers to the accessibility of variables, functions, and objects in a particular part of the code. JavaScript uses lexical scoping, which means that the scope of a variable or function is determined by its location in the code.
Before getting into scope we have to know how we can declare variables in javascript. There are three methods in javascript to declare variables ie. let var and const.

  • The variables declared with a var will have function scope. Example
function foo() {
  var a = 1;
  console.log(a);
}

foo(); // Output: 1
console.log(a); // Error: a is not defined

Enter fullscreen mode Exit fullscreen mode
  • If a variable is declared in a function using var then it can be accessible in the function only but if it is defined in the block it will have block scope it can be accessed anywhere in the program Example
if(2 < 3){
  var a = 1;
  console.log(a);
}

console.log(a); // Output: 1

Enter fullscreen mode Exit fullscreen mode
  • In javascript nested functions can access variables in their parent function these nested functions are called closures. Example
  function outer() {
  var a = 1;

  function inner() {
    var b = 2;
    console.log(a, b);
  }

  inner();
}

outer(); // Output: 1 2
Enter fullscreen mode Exit fullscreen mode
  • The variables declared using let and const will have block scope means any variable declared within curly braces cannot accessible from outside of curly braces. Example
if(2 < 3){
  var a = 1;
  console.log(a);
}

console.log(a); // Output: undefined

Enter fullscreen mode Exit fullscreen mode
  • Nested functions can access variables declared in an outer function
  • If a variable is declared outside all functions and blocks it will have global scope means it can be accessed from anywhere in the program.

Hoisting

In javascript, execution will have two phases one is the creation and another one is execution. In the creation phase all variables will be created in memory with the default value undefined and all the functions will store fully. Here only variables declared with var and regular functions will be created in the creation phase. This is known as hoisting

  • In the execution phase variable initialization will take place Example
console.log(hi) // undefined
console.log(hello) // reference error

var hi =90
let hello=99

Enter fullscreen mode Exit fullscreen mode
var hii=44
hi()

function hi(){
    console.log(hii);// output: 44
}
Enter fullscreen mode Exit fullscreen mode

Closures

In JavaScript, a closure is created when a function is defined inside another function and the inner function is returned or passed as a reference to a variable outside its enclosing function. The closure captures and retains the values of all the variables that were in scope at the time of its creation, even after the outer function has returned. Closures allow you to create private variables and functions that are inaccessible from outside the function in which they were defined

Example

function outerFunction(x) {
  function innerFunction(y) {
    return x + y;
  }
  return innerFunction;
}

let addFive = outerFunction(5);
console.log(addFive(3)); // Output: 8

Enter fullscreen mode Exit fullscreen mode

In this example, outerFunction returns innerFunction, which is then assigned to the variable addFive. When addFive is called with an argument of 3, it returns 8. The closure is created when innerFunction is defined inside outerFunction, and it captures the value of x, which is 5. Even though outerFunction has returned and its local variables are no longer in scope, the closure retains the value of x and can still access it when innerFunction is called.

Applications of closures

  1. Private variables and methods: Closures can be used to create private variables and methods that are inaccessible from outside the function in which they were defined. This can be useful for preventing unintended modifications to your code. For example:
function counter() {
  let count = 0;
  function increment() {
    count++;
    console.log(count);
  }
  return increment;
}

let c = counter();
c(); // Output: 1
c(); // Output: 2
c(); // Output: 3
Enter fullscreen mode Exit fullscreen mode
  1. Memoization: Closures can be used to implement memoization, which is a technique for caching the results of expensive function calls to improve performance. For example:
function memoize(func) {
  let cache = {};
  return function(...args) {
    let key = JSON.stringify(args);
    if (cache[key]) {
      console.log('Retrieving from cache');
      return cache[key];
    }
    else {
      console.log('Calculating result');
      let result = func(...args);
      cache[key] = result;
      return result;
    }
  };
}

function fibonacci(n) {
  if (n < 2) return n;
  return fibonacci(n-1) + fibonacci(n-2);
}

let memoizedFibonacci = memoize(fibonacci);
console.log(memoizedFibonacci(10)); // Output: 55
console.log(memoizedFibonacci(10)); // Output: Retrieving from cache, 55

Enter fullscreen mode Exit fullscreen mode
  1. Callback functions: Closures can be used to create callback functions that have access to variables from the parent function. This can be useful for implementing event handlers and other asynchronous operations. For example:
function doSomething(callback) {
  let data = 'hello world';
  setTimeout(function() {
    callback(data);
  }, 1000);
}

function callbackFunction(data) {
  console.log(data.toUpperCase());
}

doSomething(callbackFunction); // Output: HELLO WORLD
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
jonrandy profile image
Jon Randy 🎖️ • Edited

In JavaScript, a closure is created when a function is defined inside another function...

Incorrect - a closure is created whenever a function is created. It makes no difference if it was inside another function or not. A closure is the combination of a function bundled together with references to its surrounding state. Every function has an associated closure.