HomeNotesJavascript Notes

javascript notes

Published Jan 6, 2025
Updated Jan 8, 2025
3 minutes read

JavaScript and React Concepts

Table of Contents

JavaScript

React

Hoisting

When JavaScript code is executed, it is first parsed. During this parsing, variable and function declarations are "hoisted" to the top of their scope. However, only the declaration is hoisted, not the initialization.

Note: Var declaration are not block scoped let & const are block scoped

example

if (Math.random() > 0.5) {
  var x = 1;
} else {
  var x = 2;
}
console.log(x);
/// no reference error will be thrown here
 

Any of the following behaviors may be regarded as hoisting:

  1. Being able to use a variable's value in its scope before the line it is declared. ("Value hoisting")
  2. Being able to reference a variable in its scope before the line it is declared, without throwing a ReferenceError, but the value is always undefined. ("Declaration hoisting")
  3. The declaration of the variable causes behavior changes in its scope before the line in which it is declared.
  4. The side effects of a declaration are produced before evaluating the rest of the code that contains it

The four function declarations above are hoisted with type 1 behavior; var declaration is hoisted with type 2 behavior; let, const, and class declarations (also collectively called lexical declarations) are hoisted with type 3 behavior; import declarations are hoisted with type 1 and type 4 behavior.

Example:

console.log(a); // undefined
var a = 5;
console.log(a); // 5

Internally, the code is interpreted as:

var a; // declaration is hoisted
console.log(a); // undefined
a = 5; // initialization happens here
console.log(a); // 5

Temporal dead zone (TDZ)

A variable declared with let, const, or class is said to be in a "temporal dead zone" (TDZ) from the start of the block until code execution reaches the place where the variable is declared and initialized.

Some prefer to see let, const, and class as non-hoisting, because the temporal dead zone strictly forbids any use of the variable before its declaration. This dissent is fine, since hoisting is not a universally-agreed term. However, the temporal dead zone can cause other observable changes in its scope, which suggests there's some form of hoisting:

 
// temporal dead zone depends on the order of execution time rather than the order in which the code is written 
 
{
    const func = () => {console.log(letVar)}
    // function is defined here 
    let letVar = 3; 
    func()
    // but it is called here 
    
}
 

Closure

A function bundled up with it's lexical score is called closure

practical example of how closure's are used

function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}
 
const add5 = makeAdder(5);
const add10 = makeAdder(10);
 
console.log(add5(2)); // 7
console.log(add10(2)); // 12
 

Promise

Promsie is a proxy for tasks that will take some time to execute, like an api call, so instead of waiting there promises returns a state "Pending, fullfiled, rejected", which tells us if the promise is executed or not, if it is rejected or fullfiled .then is called myPromise.then(executed if fullfiled, executed if rejected)

const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("foo");
  }, 3000);
});
 
// the above is one promise which calls resolves foo after 3 ms 
myPromise
  .then((value) => `${value} and bar \n`)
  .then((value) => `${value} and bar again \n`)
  .then((value) => `${value} and again \n`)
  .then((value) => `${value} and again \n`)
  .then((value) => {
    console.log(value);
  })
  .catch((err) => {
    console.error(err);
  });
 
 

Event Loop + Promise

JavaScript maintains a job queue. Each time, JavaScript picks a job from the queue and executes it to completion. A promise can participate in more than one chain. For the following code, the fulfillment of promiseA will cause both handleFulfilled1 and handleFulfilled2 to be added to the job queue. Because handleFulfilled1 is registered first, it will be invoked first.

const promiseA = new Promise(myExecutorFunc);
const promiseB = promiseA.then(handleFulfilled1, handleRejected1);
const promiseC = promiseA.then(handleFulfilled2, handleRejected2);
 

The order of executing is

  1. promise a invoked
  2. immedidate loggin
  3. asynchrnous logging

this is because 1 & 2 and synchronous tasks and 3 is added to micro tasks list

const promiseA = new Promise((resolve, reject) => {
    console.log("promise A invoked")
  resolve(777);
});
 
promiseA.then((val) => console.log("asynchronous logging has val:", val));
 
console.log("immediate logging");
 

Currying

Currying is the process of taking a function with multiple arguments and turning it into a sequence of functions each with only a single argument