Demystifying Scopes

Demystifying Scopes

ยท

4 min read

Scopes are properties of name bindings which tells us what and which are the name bindings that are accessible at a particular part of the program or at a given point of time. Name bindings refers to the name associated with an entity. Entity could be a variable, a function etc. The rules that define these scopes are called scope rules. Generally, there are two types of Scopes - Lexical Scope and Dynamic Scope. Lexical Scope resolves the name bindings based on where they are defined (lexical context) and their location in the source code. Dynamic Scope resolves the name bindings based on the program state, which is determined by the execution context (runtime context). Javascript is a lexically scoped language. All the names which are associated with variables, functions etc are resolved based on where they are defined and what is their location in source code. Normally in lexical scope, the child functions searches the names in the local lexical context, if it fails, it moves to the outer function and searches it's local lexical context. This continues till it reaches the outermost function.

scopes.jpeg

The above image is a clear representation of lexical scoping, where Function C can access all the variables present in Function C, Function B, Function A and Global Function; Function B can access all the variables present in Function B, Function A and Global Function; Function A can access all the variables present in Function A and Global Function while Global Function can access only the variables present in the Global Function. I hope now you have got a clear picture on how lexical scoping works in Javascript. Now, let's apply this knowledge in a real code snippet and try to understand it more deeply.

Case 1

var myCar = {
  model: "Nissan",
  type: "XUV",
  color: "black",
  price: 1500000
}
function calLoanPercentage(number) {
  return myCar.price * number/100;
}
console.log(calLoadPercentage(25));

As the Javascript engine parses the above code snippet, it prepares a scope plan for all the name bindings that's present in the code. In this case, it starts with myCar. It checks whether this is present or not. If it's not present, it creates a scope (Global Scope as it's the outermost function) for this name binding (myCar) and moves forward. Now, it encounters a new name binding, which is the function, calLoanPercentage(number). This name binding will also be having the same scope as that of myCar as both of them are at the same level. In case of functions, an additional scope called local scope, will also be created, where all the parameters and other variables present inside the function, will be of that scope. These name bindings cannot be called from the outer functions. During the execution phase, Javascript engine starts executing the code line by line. At first, it will check if there is a name binding called myCar, if it's present, it will assign it's value. Then it moves directly to the console statement. In the console statement, we are calling the function calLoanPercentage(25) with an argument value 25. As soon as the javascript executes this, it checks for the name binding calLoanPercentage() in the memory, as it's present, it takes the function definition and starts executing. At first, it will define it's parameters and assign it with the argument value 25. After which, it will return myCar.price * number/100. While executing this statement, it will first try to find myCar in the local memory. As it does not find, it will move to the outer function and searches in its memory. As it finds, it will grab the value and checks for the property price, which is present, and hence returns the value 1500000. Similarly, it searches for the variable, number, in it's local memory. As it finds, it will grab the value and evaluate the expression. The evaluated value is then passed as an argument to the console.log() method, which prints the value to the console.

Case 2

var functionExpression = function printOne() {
  var text = "hello";
  console.log(text);
}
functionExpression() // prints "hello"
printOne() // ReferenceError: printOne is not defined

In the above code, we have made use of named function expressions. In this case, the name printOne will be in the local scope of the function and not in the global scope. This is the reason why we get a Reference Error when we try to call the function by it's name printOne.

So how does scoping works in the cases of const and let declarations ???. Well, I will be soon covering this in detail in my next blog, hold tight. Till then, if you feel this article was useful, please do show your love and share this to your fellow beings via your social media who could make maximum use of this. Always feel free to connect with me on twitter, linkedIn or email.

Until we meet again, The Mallu Dev signing off ๐Ÿ‘‹ Cheers ๐Ÿฅ‚