Single Thread
JavaScript is a synchronous, Single-threaded language. Javascript has only one call stack. Whatever is at the top of the call stack will run first and it will go till the last line by line. With the help of the browser Web API's Javascript can behave like asynchronous and multi-threaded language but internally it is still executed line by line.
Scopes in javascript
What is a scope?
Scope is the set of rules that determines where and how a variable can be looked-up. This look-up may be for the purposes of assigning to the variable, or it may be for the purposes of retrieving its value.
Scope is of 3 types:
- Function Scope
- Block Scope
- Global Scope
Function Scope
Variables and Parameters declared inside a function are accessible inside the function but not outside the function.
function scoped(number) {
const incrementedNumber = number + 4;
console.log(number);
//22
console.log(incrementedNumber);
// 26
}
scoped(22);
console.log(number)
// ReferenceError: number is not defined
The variable number and incrementedNumber are functions scoped and thus they throw an error when someone tries to access them.
Block Scope
Block Scope is defined with curly braces. It is separated by { }.
// Oustside Block
let x = 55;
{
// Inside Block
ket x = 33;
console.log("Inside Block: ", x)
}
console.log("Outside Block: ",x)
// Inside Block: 33
// Outside Blocl: 55
Global Scope
In the global scope, the variable can be accessed from any part of the JavaScript code.
var a = 50;
function func() {
// Function Scope
console.log(a);
}
func();
{
// Block Scope
console.log(a);
}
// 50
// 50
Call Stack
JavaScript controls the creation, execution, control, and deletion of Execution Context using callStack. The call stack is basically a stack data structure that follows the Last In First Out (LIFO) principle. Call Stack tracks different Execution Contexts, whenever a new execution context is created, it got pushed in to call stack and after completion, it got pops out. And the execution of the next execution context starts. Global Execution Context is last at Call Stack. Execution context that is at top of Call Stack will only get executed.
let pensil = "pensil";
function run1(){
let rubber = "rubber";
function run2(){
let cutter = "cutter";
}
}
Hoisting
JavaScript before executing the code parses it and adds to its own memory every function and variable declaration it finds, and holds in memory. This is called hoisting.
We have some different behaviors for function declarations and function expressions.
With function declarations, we can call a function before it’s defined, and our code will work. In the other cases, we’ll have errors.
A general rule of thumb is to always define functions, variables, objects, and classes before using them, to avoid surprises.
Suppose we have a function:
function bark() {
console.log('vow!')
}
Due to hoisting, we can technically invoke bark()
before it is declared:
bark()
function bark() {
console.log('vow!')
}
With functions, this only happens for function declarations. Like in the case above.
Not with function expressions.
This is a function expression:
bark()
var bark = function() {
console.log('vow!')
}
In this case, the var declaration is hoisted and initialized with undefined as a value, something like this:
var bark = undefined
bark()
bark = function() {
console.log('vow!')
}
Running this code will give you a ``` TypeError: bark is not a function error
const and let declarations are hoisted, too, but they are not initialized to undefined like var.
const bark = function() { console.log('vow!') }
or
let bark = function bark() { console.log('vow!') }
In this case, if you invoke bark() before declaring it, it will give you a
ReferenceError: Cannot access 'bark' ``` before initialization error.