In this article, we will learn about Variable Masking which is also known as Variable Shadowing i.e. a variable with the same name will shadow the variable in the outer scope. When a variable is masked, the masked variable is completely inaccessible using that variable name. The scope is hierarchical thus we can enter new scope without hampering the old one.
Â
Where can it occur?
- Methods or Functions.
- Callback Functions.
- Block Scope.
Note: It can prevent any changes or reassignments to the variables defined in the outer scope from within the inner scope.
Example 1:
Javascript
{ Â Â Â Â // block 1 Â Â Â Â const x = 'Hi' ; Â Â Â Â console.log(x); // logs "Hi" } // logs "undefined" as x is out of scope console.log( typeof x); Â Â { Â Â Â Â // block 2 Â Â Â Â const x = 1; Â Â Â Â console.log(x); // logs "1" } // logs "undefined" as x is out of scope console.log( typeof x); |
Output:
Â
Example 2: Now, we will observe what happens when we have nested scopes:Â
Javascript
{     // outer block     let x = 'Hi' ;     console.log(x); // logs "Hi"     {         // inner block         let x = 1;         console.log(x); // logs "1"     }     console.log(x); // logs "Hi" } // logs "undefined" as x is out of scope console.log( typeof x); |
Output:
Variable masking in nested scopes
Explanation: In the inner block, variable x is distinct from the outer block with the same name.It masks(hides) the x that’s defined in the outer scope. When execution enters the inner block, we have no way of accessing the variable in the outer scope as it has the same name! A new variable x is defined with variables in scope. Here is another example where x came into the scope and then exited scope before the second variable named x did the same.
Example:Â
Javascript
{     // outer block     let x = { color: "blue" };     let y = x; // y and x refer to the same object     let z = 3;     {         // inner block         let x = 5; // outer x now masked         console.log(x); // logs 5         console.log(y.color); // logs "blue";         // object pointed to by         // y (and x in the outer scope) is         // still in scope         y.color = "red" ;         console.log(z); // logs 3; z has not been masked     }     // logs "red"; object modified in inner scope     console.log(x.color);           // logs "red"; x and y point to the same object     console.log(y.color);           console.log(z); // logs 3 } |
Output:
Â
Note: Variable masking should be avoided as it can disturb the intention and clarity of the program, which could lead to hidden bugs and unintended results.
How should we avoid it: Variable masking(shadowing) can be avoided by renaming the variable’s unambiguous names.
Example:
Javascript
let girl = 'Radha' ;   [ 'Ram' , 'Raj' , 'Ramesh' ].forEach(boy => {   //variable 'girl' defined is accessible in the inner scope.       // Radha Radha Radha (repeated three times in each loop)   console.log(girl);       // Ram Raj Ramesh   console.log(boy); }); |
Output:
Â
This concludes that it is the practice of naming two variables( a global and local variable/local variable and a callback function parameter) with the same name which coexists in a scope where these variables are accessible. The scope chain determines what variables are in scope: all variables in the current scope chain are in scope, and (as long as they’re not masked), can be accessed.