javascript notes
JavaScript and React Concepts
Table of Contents
JavaScript
React
- Reconciliation
- Hooks
- Class vs Functional Components
- Memoization
- Higher Order Components
- Performance
- React Router
- Caching
- Security
- Improving Performance
- Memory Leaks
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:
- Being able to use a variable's value in its scope before the line it is declared. ("Value hoisting")
- 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")
- The declaration of the variable causes behavior changes in its scope before the line in which it is declared.
- 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
- promise a invoked
- immedidate loggin
- 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