Skip to content

Latest commit

 

History

History
256 lines (212 loc) · 5.56 KB

File metadata and controls

256 lines (212 loc) · 5.56 KB

Episode 9: Block Scope and Shadowing in JavaScript

Block

  • Block is defined by curly braces {}. The block is used to combine multiple JS statements into one group.

Why block {} is required?

  • The group of multiple statements is used where the JS engine expects one statement like an if statement because "if" expects single statements syntactically but we're using a group of statements to do that we use block {}.
  • Block is compulsory to have multiple statements.
  {
    //group of code
  }

Example 1:

  {
    var a = 10;
    console.log(a);
  }

Output 1:

  10

Block Scope

  • The variables and functions that we can access inside the block it's known as block scope.

Example 1:

  {
    var a = 10; // Global Scope

    //let and const are block scope
    let b = 20;
    const c = 30;
  }
  • let and const are hoisted in separate memory space and reserved as an undefined.
  • let and const are block scope means can't be accessed out of stock.

Example 2:

  {
    var a = 10;
    let b = 20;
    const c = 30;
   
    console.log(a);//10
    console.log(b);//20
    console.log(c);//30
  }

  console.log(a);//10
  console.log(b);
  console.log(c);

Output 2:

  Uncaught ReferenceError: b is not defined at :12:15
  • The moment we're executing the line console.log(b); the block scope is removed in the browser.

Shadowing

  • If we have a same named variable outside of the block {}, that variable is going to be shadowed by the variable inside the block because both are pointing to same memory location.

Example 3 - using var:

  var a = 100;
  {
    var a = 10; //this variable shadows the above 'a' = 100 variable
    var b = 20;
    const c = 30;

    console.log(a);//10 - because of shadowing, 10 is printed
    console.log(b);
    console.log(c);
  }
  console.log(a);//10 - because of shadowing, 10 is printed, because pointing to same memory location.

let and const are hoisted and stored in different scope. In browser, let and const are stored in the 'script' label.

Example 4 - using let:

  let b = 100; //let and const are hoisted and stored in different scope.

  {
    var a = 10; //global scope because it's a var datatype
    let b = 20; //shadowing the value of above 'b' variable
    const c = 30;
    console.log(a);//10
    console.log(b);//20 - 'b' variable got shadowed, here 'b' refers to block scope
    console.log(c);//30
  }
  console.log(b);//100 - refers to outside scope since 'b' is a let datatype

Output 4:

  10
  20
  30
  100

const is like let

Example 5:

  const c  = 100;
  {
    var a = 10;
    let b = 20;
    const c = 30; //shadowing the value of the above 'c' variable with 30
    console.log(a);//10
    console.log(b);//20
    console.log(c);//30  - 'c' variable got shadowed, here 'c' refers to block scope
  }
  console.log(c);//100 - because its outside of the scope i.e. script block[check in browser]

Output 5:

  10
  20
  30
  100

Shadowing behaves in a similar way in functions as well.

Example 6:

  var c = 100;
  function x(){
    const c = 10; //shadowing the value of the above 'c' variable with 10
    console.log(c);//10 - 'c' variable got shadowed, here 'c' refers to block scope
  }
  x();
  console.log(c);//100 - because its outside of the scope i.e. script block[check in browser]

Output 6:

  10
  100

Illegal Shadowing in case of let

  • We can't shadow a let with a var in a block scope. It throws an error because it's crossing the boundary of its scope.

Example 7: - Invalid let -> var

  let a = 20;
  {
    //we can do it with **let** type
    var a = 20; //SyntaxError
  }

Output 7:

  Uncaught SyntaxError: Identifier 'a' has already been declared

Example 8: - Valid var -> let

    var a = 20;
    {
      let a = 40;//shadowed
      console.log(a);
    }

Output 8:

  40

Try implementing illegal shadowing in case of functions

Example 9: - Valid let -> var

  let a = 20;
  function x(){
    var a = 20;
  }

Code Explanation

  • This program doesn't throw any error at all because var has its own function boundaries.
  • It's not interfering with
    let a = 20
  • This is totally valid. So, we can't call it illegal shadowing.

Illegal shadowing in case of const

Example 10:

  const a  = 20;
  {
    const a  = 30; //shadowing a variable
    console.log(a);//30
  }
  • works fine because it's in the same memory.

Output 10:

  30

Block scope also follows the lexical scope

Lexical Scope

  //outer
  const a = 20;
  {
    //inner-1
    const a = 100;
    {
      //inner-2
      const a = 200; //shadowing 'a' variable with 200. since const is a block scope.
      console.log(a);//200 - because 'a' got shadowed
    }
    console.log(a);//100 - shadowing 'a' variable with 100. since const is a block scope.
  }
  console.log(a);//20 - global scope

Output 11:

    200
    100
    20
  

Code Explanation

  1. console.log(a); in inner-2 block, if 'a' variable isn't available. Then, it checks 'a' in the lexical environment of its parent i.e. a=100
  2. If 'a' is not available the inner-1 block. Then, it checks 'a' in the lexical environment of its parent i.e. outer block. i.e. Global Execution Context a=20.

Note

Scope is same for normal functions and arrow functions

Block scope rules are the same as well.