This article will explain the *Scope, Single Thread, Call Stack, and Hoisting * concepts to reduce confusion during interviews. Similar to a brief reminder before an interview.
What are scopes in JavaScript?
As the name says, the scope is nothing but "the extent of the area." In other words, its limitations.
In terms of coding, where is the variable declared? And from where can it be accessed?
It's simple, right, so now we will discuss why and what those limitations are or Scopes.
There are three essential Scopes in JS. One is the Global level
Scope, the second is the Function level,
and the Block level
Scope.
Global Scope
In the global scope, the variables inside of this scope can be accessed from anywhere inside the JS application. Example:
var a = 10;
let b = 20;
function write () {
console.log(b);
}
write();
Output:
The above example shows that the variable can be accessed inside and outside a function/block.
Here, only a
is visible under the window object. In a way, You can consider the Window object as a global scope. But we cannot view the b
from the above example. It uses the ** Let/const ** properties to declare a variable. However, b
can be accessed by calling the write()
function, which proves our global scope theory. Although using a global variable is not a good practice except in exceptional cases. You will know the reasons later in this article.
function scope
you can also refer to the local scope; It is only accessible within the function. It can not access any variables/values declared outside the function. For an Example:
var a = 10;
let b = 20;
function write () {
var c = 30;
}
console.log(c);
Output: you can see that when we try to print the c
value, it's throwing a reference error saying that c
is not defined. Because we declared the variable c
inside the function, it is not accessible outside of that function.
The problem with var
is that if it is a for loop, while loop, if statement, switch statement, or any block asides of a function, it is not scoped locally. It works like a global scope except in function. So we can say var
only has functional scope.
For example:
if (true) {
var c = 'hello';
}
console.log(c)
Output:
(base) praveenalluri@Praveens-MacBook-Air training % node test.js
hello
See, though defining c
inside a local scope/object, c
is still accessible outside the local scope. This may create name clash conflicts in your JS application. This is why let and const are introduced to address this issue in the form of block scope.
Blockscope
So what is a block? Anything in between the curly braces is called a block. Unlike Var, LET/CONST
are locally scoped. Not just to functions but all call blocks. So you can call LET and CONST are block scoped.
Let's see a real-time example.
let a = 10;
if(true) {
let a = 2000;
console.log(a);
}
console.log(a);
Output:
(base) praveenalluri@Praveens-MacBook-Air training % node test.js
2000
10
In the above example, you can see that there is no name conflict though we defined a
twice using LET/CONST. That's because the inside block scope variable a
doesn't know or can not access the outside variable a
.
That's all about scopes related to Var, Let, and Const in Javascript. The scope is all about where the program uses the variable.
Let's move to our next topic, Single Thread.
Is Javascript Single threaded Async language?
In fact, JavaScript is a single-threaded synchronous language with asynchronous capabilities. It means In the core of JS, it works synchronously. However, we do have asynchronous capabilities. We have web APIs that can help us do things asynchronously. In JS, one thread of execution runs at a time, and this has caused confusion among some people. Let's understand with this a simple demo.
function hi(){
setTimeout(() => {
console.log('hi number 1')
}, 1000);
};
hi();
console.log('hi number 2')
Output:
(base) praveenalluri@Praveens-MacBook-Air training % node test.js
hi number 2
hi number 1
If you see the above code, it started executing the first line of code and all those declarations. Later it called function hi()
and it called set timeout
and then passed the parameters. It past something that says hey! Here's some code to be executed later, and here's the timeout. But it doesn't run that last, get queued up somewhere. (you will learn how and where it's storing those values later in this article).
There is some event Queue that was eventually going to process this. It's scheduled for execution in about 1000 milliseconds. And finally, it is called console.log(hi number 2)
. So our application started up. It wrote console.log(), a second went by, and hi() executed.
Now, I will add some confusion to the code. I will add something into the main threaded execution that will never have a chance to process the things in the event queue. I'm adding a while loop with no parameters.
Now we run it again, and I got my hi number 2
, and I never get hi number 1
, and that's to be expected if you understand how this works. This is queued up as soon as the system has time to process the event Queue it will process. But our main thread execution is stuck right now, just doing nothing. Now there's a technique that you should know about JS. There are times when you do have to do things that will take a long time, and you do want to allow your javascript to process items that are queued up that are ready to run. Let's understand this with a small demo.
Like before, this will get stuck; however, it gets stuck by putting things in the event queue. So think about this, It will execute the same things before it looks at your 'console.log(hi)', and it will call a function that will call this set timer and execute the set timeout right away. And then queue up something for execution later. So we'll get stuck in this loop, but it's going through the events queue now. If it's something else on the event queue, it will have an opportunity to run.
In simple words, when I run this above code, It gives the output value hi number 2
followed by hi number 1
, and then it is stuck. Because even though we've put this lock-up function **"hi3()" **in the middle of our application. We're still going through the event queue and processing the other things in the event queue.
That's it. I think you now understand the async and single-threaded concepts in javascript language.
call stack in JS
A call stack keeps track of our functions. It is a stack of functions it manages, which we call the execution contexts. At the bottom of the call stack is our global execution context. That will always be at the bottom, and our functions will be stacked on top. A Stack is a data structure, so it doesn't have to be the JavaScript call stack. You can create any stack, just like in an array or queue. Stacks are LIFO which stands for “last in first out” what that means is the last thing in is always going to be the first thing out. Let's look at some sample code and what that would look like on the call stack.
function one() {
console.log("one");
two();
}
function two() {
console.log("two");
three();
}
function three() {
console.log("three");
}
one();
Output:
(base) praveenalluri@Praveens-MacBook-Air training % node test.js
one
two
three
Let's see the below example.
%[https://youtu.be/wdbIMqz4aM8]
Now, I'm going into the sources tab and putting a breakpoint right at first where this whole thing starts, and I will reload the browser, so it's paused right now. You can see we have created the global execution context. It's in our call stack, and I'm going into the first function one(), so I'll click this arrow key on the right top. Now you can see that function one
pushed onto the stack. Then we're going to go to the console.log, and once again, I click this arrow key again, it's going to run function two(). So notice now that one
is still there. It means we're still in the first function, one(), because that's where two() is called, so two() is now on the stack and then call three() so click the arrow again, three() now three gets pushed onto the stack, and then I will go ahead and execute three() now it gets popped off, later two() that gets popped off and then one(). So it's always last in, first out, OK, so that's a pretty basic example of how the call stack works. As you build big projects, pop into the sources tab and look at the call stack. Obviously, it'll be much more complicated when you're working on an actual project.
Hoisting
Hoisting is a phenomenon in JavaScript by which you can access these variables and functions even before you have initialized or given some value to them. You can access them without any errors. So wherever this let variable is present in the program, it does not matter; you can access it anywhere. So let me show you some examples.
hoist();
console.log(x);
var x=7;
console.log(hoist);
function hoist(){
console.log('hoisting test');
}
Output :
(base) praveenalluri@Praveens-MacBook-Air training % node test.js
hoisting test
undefined
[Function: hoist]
If you observe correctly, I called the function and variable before initializing them, but you can see the values in the output without errors. If it is any other programming language, it will throw an error. because hoisting concept in Javascript it wont throw any errors. When ever the Js program runs it creates Global execution context
which has two components, Memory and code. the first phase will be scan the entire JS program and allocate space to variables and functions in the memory component before executing the program. That is why our second result is saying undefined because it already allocated undefined memory
to x
before knowing it's value.
That's all folks. see you in the next article. Watch out for more space.
Stay peace
Top comments (0)