โ Scope ๐ฅ
Scope defines the area, where functions, variables and other things are available or can be accessed. In layman's terms, scope means where to look for things, what things I can use and what I cannot!
Let's take an example, here we are defining a variable inner inside a block ({...}
) and we are trying to access it both inside the block as well as outside the block.
{
let inner = "I am inside a block";
console.log(inner);
}
console.log(inner); //ReferenceError: inner is not defined
Here as variable inner
is declared inside a block, we are unable to access it outside the block or we can say, the scope of variable inner
is limited to that block only, we cannot use it outside that block.
How are scopes determined?
To answer this question we need to figure out how JavaScript runs our code. Abstractly speaking, JS engine runs our code in two phases.
- Compilation/Scanning/Parsing of code
- Execution
The execution part is simple, it just runs our code line by line. But what is parsing?
Parsing of code means, that JS, before executing the code, scans the whole code and does multiple things including optimization, memory allocation, etc. One of which is setting scopes for our variables. Let's see how it does that with a code snippet and a diagram.
// Global Scope
var names = ["Prateek Budhiraja", "Anirudh", "Hitesh Choudhary", "Anurag"];
function getFullName(list) {
// Function getFullName's scope
let fullName = [];
for (let name of list) {
// For scope
if (name.includes(" ")) {
fullName.push(name);
}
}
return fullName;
}
console.log(getFullName(names));
So what complication does is, it categorises every element according to the scope!
Scope/Access Rule:
- If the variable is not declared in the current scope, the next outer/enclosing scope will be consulted and this process of stepping out one level of scope nesting continues until either a matching variable declaration can be found, or the global scope is reached and there's nowhere else to go.
For example in our above code:
- In the global scope, we can only access variables we declared in the global scope. i.e.
names
. - In function scope, we can access everything we declared in the function scope, and along with it, we can also access variables of the global scope. i.e.
names
,fullName
,list
. - Similarly in for scope, we can access everything from its scope, its parent, i.e. function and also from the global scope. So from
for
, we can accessnames
,list
,fullName
,name
.
โ Hoisting
Hoisting is a process where javascript moves our functions, variables and class declarations to the top of their scope before the execution of the program, which we can safely call our function before they are declared. Example:
sayHello();
function sayHello() {
console.log("Hey, friends ๐");
}
We can also hoist variables but they are usually avoided as they tend to give unexpected errors. Example:
if (isLoggedIn) {
console.log("Show dashboard");
} else {
console.log("Show login page");
}
var isLoggedIn = true;
So the above code runs, just the problem is even though we see that we assigned true
to the variable isLoggedIn
, the else part is getting executed, this is because isLoggedIn
variable is scanned and made available so it is not giving any errors, but it is assigned a value undefined
, and as undefined
is a falsy value, therefore the condition fails and it executes else part.
Rules for hoisting
- Function declarations are scanned and made available.
- Variable declarations are scanned and made undefined.
We have seen variables declared with var
but if we are declaring variables with let and const, they are also hoisted but, unlike var, are not initialized with a default value. An exception will be thrown if a variable declared with let or const is read before it is initialized.
Example using both the concepts (scope and hoisting)
function sayHello() {
let greetings = "Hello";
{ // ๐ scope starts
greetings = "hey"; //ReferenceError: Cannot access 'greetings' before initialization
let greetings = "Hola";
console.log(greetings);
}
console.log(greetings);
}
sayHello();
We got that error because the greetings
variable is used (the code inside {...}
) before its being initialized in that scope, even though it is declared/initialized in the outer scope, because it only consults the outer scope when the variable is not in the current scope, but as it is in the current scope, it fails!
โ JS is SingleThreaded
JavaScript is a synchronous single-thread programming language. We all heard it, we all read it, and it is the first line someone says while introducing javascript! But what does it means?
It simply means that JS will execute one statement at one time. It picks up one line, executes it and only goes to another line when the first line finishes its execution.
We can visualize it as a memory stack, one line of code comes, it executes and it gets pops out of the execution context, or a big function comes on it gets executed and then it goes away and so on.
โ Call Stack
Callstack is nothing but a place where javascript keeps track of the execution of the code. With it, we can see which line of code or function is currently running, what will happen if this function ends, or what will happen if a function calls another function etc.
Let's take an example:
function calculateTip() {
return 5;
}
function payBill(amnt) {
let getTip = calculateTip();
return `Total bill is ${amnt + getTip}`;
}
console.log(payBill(100));
The above is a simple JS program, which has 2 functions, one is payBill
which is calling another function, called calculateTip
, let's see how JS will execute this.
- Java Script will first scan the whole code and will make the functions available for use.
- It will encounter a function call (
payBill(100)
) it will addpayBill
function to the call stack. - Now the function will start it's execution.
- While executing the function, it finds a function call for
calculateTip()
. - We already have a function in the call stack, but as we get another function call, javascript will add
calculateTip
to the call stack. And as javascript is a single-threaded language,calculateTip
function will start executing andpayBill
will be halted. calculateTip
finishes its work and returns some results. As soon as javascript encounters thereturn
statement, it returns the value and javascript will removecalculateTip
from the call stack.- Now we are back to our
payBill
function, now javascript also keeps track of where we need to resume, so instead of executing the function again, it knows from where we need to resume the execution. - After encountering the
return
statement inpayBill
javascript will return the value to the place from where the function was called and it will remove it from the call stack.
I hope you learned something new, if you wish to read more about then, you can refer to the links below.
Happy Learning ๐ซ