⏱ 0:01est. 30 min
Practice Dec 2021
// --
// IIFE
var greet = (function (name) {
return `Hi, ${name}`;
})("Nishant");
console.log(greet); // Hi, Nishant
// --
// Perfect JS Code
{
name: "John";
} // {name: 'John'}
// --
// Perfect JS Code
("I'm a string"); //"I'm a string"
// --
// IIFE
(function (name) {
console.log(name);
})("Testing IIFE"); // Testing IIFE
// --
// async/await
async function f() {
return 1;
}
// Keyword async means the function will always return a promise
console.log(f()); //Promise { 1 }
// The function returns resolved promise with the result of 1
console.log(f().then((result) => console.log(result))); //1
// Following function is same as f
async function f1() {
return Promise.resolve(1);
}
// async ensures the function returns promise and wraps non-promise in it.
// await - works only inside async function
// await - makes JavaScript wait until that promise settles and returns its result
// await - That doesn’t cost any CPU resources. JavaScript engine can do other jobs - execute other scripts, handle events, etc.
async function f2() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("done!"), 1000);
});
let result = await promise; // wait until the promise is resolved
console.log(result); // done!
}
f2();
// async/await example showAvatar
async function showAvatar() {
// read our JSON
let response = await fetch("/article/promise-chaining/user.json");
let user = await response.json();
// read github user
let githubResponse = await fetch(`https://api.github.com/users/${user.name}`);
let githubUser = await githubResponse.json();
// show the avatar
let img = document.createElement("img");
img.src = githubUser.avatar_url;
img.className = "promise-avatar-example";
document.body.append(img);
// wait 3 seconds
await new Promise((resolve, result) => {
setTimeout(resolve, 3000);
});
img.remove();
// return result
return githubUser;
}
// async class method
class Waiter {
async wait() {
// return 1;
return await Promise.resolve(1);
}
}
new Waiter().wait().then((result) => console.log(result)); // 1
// in case of rejection, promise throws an error
async function f3() {
await Promise.reject(new Error("Woops!"));
}
// if we forget to add .catch, then we get unhandled promise error
f3().catch((error) => console.log(error));
async function fakeFetch(url) {
let p = new Promise((resolve, reject) => {
setTimeout(() => resolve(url), 1000);
});
let response = await p;
return response;
}
// async/await works well with Promise.all
// wait for array of results
async function f4() {
let result = await Promise.all([fakeFetch("url1"), fakeFetch("url2")]);
console.log(result); //[ 'url1', 'url2' ]
}
f4();
// Call async from non-async
// We have a "regular" function called f.
// How can you call the async function wait() and use its result inside of f?
async function wait() {
await new Promise((resolve) => setTimeout(resolve, 1000));
return 10;
}
function f5() {
// ...what should you write here?
// we need to call async wait() and wait to get 10
// remember, we can't use "await"
wait().then((response) => {
// shows 10 after 1 second
console.log(response);
});
}
f5();
// --
// Promise
let promise = new Promise((resolve, reject) => {
// executor (the producing code, "singer")
});
// internal properties:
// - state -- initially pending, changes to fulfilled when resolved is called or rejectedd when reject is called
// - result -- initially undefined, then changes to value when resolve(value) called or error when reject(error) is called
// Example of fulfilled promise
let promise = new Promise((resolve, reject) => {
// the function is executed automatically when the promise is constructed
// after 1 second signal that the job is done with the result "done"
setTimeout(() => resolve("Done!"), 1000);
});
// Example of rejected state
let promise = new Promise((resolve, reject) => {
// after 1 second signal that the job is finished with an error
setTimeout(() => reject(new Error("Whoops!")), 1000);
});
// then
// - the first argument .then is a function that runs when the promise is resolved, and receives the result
// - the second argument of .then is a function that runs when the promise is rejected, and receives the error.
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("done!"), 1000);
});
promise.then(
(result) => console.log(result),
(error) => console.log(error)
);
promise.catch(console);
// finally
// The call .finally(f) is similar to .then(f, f) in the sense that f always runs when the promise is settled: be it resolve or reject.
new Promise((resolve, reject) => {
setTimeout(() => resolve("result"), 2000);
})
.finally(() => console.log("Promise ready"))
.then((result) => console.log(result)); // <-- .then handles the result
// Promise ready
// result
function delay(ms) {
return new Promise((resolve, reject) => {
setTimeout(resolve, ms);
});
}
delay(3000).then(() => console.log("runs after 3 seconds"));
// --
// Bind - creates copy of the function
let basic = {
name: 'Nishant',
age: '33'
}
function callMe() {
console.log('Hi my name is ', this.name, ' and my age is ', this.age, ' and my city is ', arguments[0], ' and state is ', arguments[1]);
}
let callMeBind = callMe.bind(basic, 'Delhi');
callMeBind('DL') // Hi my name is Nishant and my age is 33 and my city is Delhi and state is DL
// Function binding
// When passing object methods as callbacks, for instance to setTimeout, there’s a known problem: "losing this".
let user = {
firstName: 'John',
sayHi() {
console.log(`Hello ${this.firstName}`);
}
}
setTimeout(user.sayHi, 1000); // Hello undefined
setTimeout(() => {
user.sayHi()
}, 1000) // Hello John
setTimeout(user.sayHi.bind(user), 1000); // Hello John
function f7() {
console.log(this);
}
let user = {
g: f7.bind(null)
}
user.g(); // window
let personTestObj = {
name: 'Nishant',
lastname: 'Mendiratta',
age: '33',
getFullName: function () {
// console.log(this); // {name: 'Nishant', lastname: 'Mendiratta', age: '33', getFullName: ƒ}
return this.name
}
}
function PersonTest() {
return console.log(`${this.getFullName()}`);
}
console.log(personTestObj.getFullName()) // Nishant
PersonTest.bind(personTestObj)(); // Nishant
let p = PersonTest.bind(personTestObj);
p() // Nishant
// Pollfill of bind
Function.prototype.bindCustom = function (ctx, ...args1) {
let fn = this;
return function(...args2) {
fn.apply(ctx, [...args1, ...args2]);
}
}
let callWithCustomBindd = PersonTest.bindCustom(personTestObj)
callWithCustomBindd(); // Nishant
let arrayToFlat = [1,2,[3],[[4]],[[[5]]]];
function flattern(arr) {
return arr.reduce((acc, item) => {
return acc.concat(Array.isArray(item) ? flattern(item): item);
}, [])
}
console.log(flattern(arrayToFlat))
let arrToReverse2 = [1, 2, 3, 4];
for(let i=0; i<arrToReverse2.length/2; i++) {
[arrToReverse2[i], arrToReverse2[arrToReverse2.length-i-1]] = [arrToReverse2[arrToReverse2.length-i-1], arrToReverse2[i]]
}
console.log(arrToReverse2);
// Array.reduce
let nums = [1,2,3,4,5]
let sum = nums.reduce((acc, num) => {
return acc+num;
}, 0);
console.log(sum);
// closure
function greet(whattosay) {
return function (name) {
console.log(whattosay, name);
}
}
greet('hi')('nishant')
// Object deep copy
const obj = {
a: 1,
b: "hello",
c: {
d: "world"
},
e: {
f: {
g: 100
}
}
};
function cloneObj (obj) {
let clone = {};
for (var prop in obj) {
if (typeof obj[prop] === "object" && obj[prop]!==null) {
clone[prop] = cloneObj(obj[prop]);
} else {
clone[prop] = obj[prop];
}
}
return clone;
}
let objCloned = cloneObj(obj);
console.log(objCloned)
function debounce (func, limit) {
let timer = null
return function(e) {
const ctx = this;
const args = arguments;
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(ctx, args);
}, limit);
}
}
const greet = () => console.log('Hello World!')
const debouncedGreet = debounce(greet, 3000)
for (let i = 0; i < 10; i++) {
debouncedGreet()
}
function throttle (func, limit) {
let flag = true;
return function() {
if (flag) {
let ctx = this;
let args = arguments;
func.apply(ctx, args);
flag = false;
setTimeout(() => {
flag = true
}, limit);
}
}
}
// Exectution context
var a = "hello";
let c = "hi";
function b() {
console.log("called b!"); // called b
console.log(a); // hello
console.log(c); // hi
}
b();
var a = "hello";
let c = "hi";
function b() {
console.log(a); // "undefined"
console.log(c); // ReferenceError: Cannot access 'c' before initialization, program will break here
var a = "hello inner"
let c = "h1 inner"
console.log("called b!"); // called b
console.log(a); // hello inner
console.log(c); // hi inner
}
b();
var myVar = 2;
// Scope chain
function a () {
console.log(myVar); // undefined
var myVar = 3;
function b() {
console.log(myVar); // 3
}
b();
}
a()
// Scope chain
var myVar = 1;
function a () {
function b() {
console.log(myVar); // 1
}
b();
}
a()
// Let, Const are hoisted differently. They are in temporal dead zone
console.log(a); // ReferenceError: Cannot access 'a' before initialization
// - a is in script block
// allocated memory, can't be accessed unless we have initialized. They are in temporal dead zone
// A variable which is hoised with let and until it goes to initailized value, it's in temporal dead zone
console.log(b); // undefined
// - b is attached to global object
// allocated memory, hoising
let a = "1";
var b = "2";
var a = "2";
let a = "1";
console.log(a); //Reference Error, Identifier 'a' has already been declared
// --
const a; // Syntax Error: Missing initializer in const declaration
a = 100;
connsole.log(a)
// --
const a = 100;
a = 10;
console.log(a) // TypeError: Assignment to constant variable.
// Currying
let multiply = function (x, y) {
return x*y;
}
let multiplyBy2 = multiply.bind(this, 2);
console.log(multiplyBy2(3))
// Currying with closure
let multiply = function (x) {
return function (y) {
console.log(x*y)
}
}
let multiplyBy2 = multiply(2);
multiplyBy2(3)
function sum(a) {
return function(b) {
if (b) {
return sum(a+b);
}
return a
}
}
console.log(sum(1)(2)(3)(4)())
/**
* Closure - https://javascript.info/closure
* A closure is a function that remembers its outer variables and can access them.
* Sum with closures https://javascript.info/closure#sum-with-closures
* sum(1)(2) = 3
* sum(5)(-1) = 4
*/
function addition (a) {
return function (b) {
if (b) {
return addition (a+b);
}
return a;
}
}
console.log(addition(1)(2)(3)())
/**
* Promise
* Exists because of callback hell problem - https://javascript.info/callbacks
*
* Basics - https://javascript.info/promise-basics
* A promise is a special JavaScript object that links the “producing code” and the “consuming code” together.
* In terms of our analogy: this is the “subscription list”
* The “producing code” takes whatever time it needs to produce the promised result, and the “promise” makes that result available to all of the subscribed code when it’s ready.
*
* let promise = new Promise((resolve, reject) => {
* // executor (the producing code, "singer")
* });
* Its arguments resolve and reject are callbacks provided by JavaScript itself.
* - resolve(value) — if the job is finished successfully, with result value.
* - reject(error) — if an error has occurred, error is the error object.
* States - pending, fulfilled, or rejected
* result - undefined, value, or error
*/
function loadScript(src) {
return new Promise(function(resolve, reject) {
let script = document.createElement('script');
script.src = src;
script.onload = () => resolve(script);
script.onerror = () => reject(new Error(`Script load error for ${src}`));
document.head.append(script);
});
}
let promiseExample = loadScript("https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js");
promiseExample.then(
script => alert(`${script.src} is loaded!`),
error => alert(`Error: ${error.message}`)
);
promiseExample.then(script => alert('Another handler...'));
// Promises
// Promises allow us to do things in the natural order. First, we run loadScript(script), and .then we write what to do with the result.
// We can call .then on a Promise as many times as we want. Each time, we’re adding a new “fan”, a new subscribing function, to the “subscription list”. More about this in the next chapter: Promises chaining.
// Callbacks
// We must have a callback function at our disposal when calling loadScript(script, callback). In other words, we must know what to do with the result before loadScript is called.
// There can be only one callback.
// Fetch - https://javascript.info/fetch
let promiseFetch = fetch(url, [options])
let response = await fetch(url);
if (response.ok) { // if HTTP-status is 200-299
// get the response body (the method explained below)
let json = await response.json();
} else {
alert("HTTP-Error: " + response.status);
}
// Fetch type async/await
React.useEffect(async () => {
const response = await fetch("https://jsonplaceholder.typicode.com/todos/");
const data = await response.json();
console.log('data', data);
}, []);
// Fetch type promise then
React.useEffect(() => {
const response = fetch("https://jsonplaceholder.typicode.com/todos/").then((response) => response.json()).then((data) {
console.log('data', data);
});
}, []);
// event bubbling and capturing. -- use cases
/**
* Event bubbling - https://www.quirksmode.org/js/events_order.html
* When you use event bubbling
/ \
---------------| |-----------------
| element1 | | |
| -----------| |----------- |
| |element2 | | | |
| ------------------------- |
| Event BUBBLING |
-----------------------------------
the event handler of element2 fires first, the event handler of element1 fires last.
* Event capturing
* When you use event capturing
| |
---------------| |-----------------
| element1 | | |
| -----------| |----------- |
| |element2 \ / | |
| ------------------------- |
| Event CAPTURING |
-----------------------------------
the event handler of element1 fires first, the event handler of element2 fires last.
*/
/**
* You, can choose whether to register an event handler in the capturing or in the bubbling phase.
* This is done through the addEventListener() method explained on the Advanced models page.
* If its last argument is true the event handler is set for the capturing phase, if it is false the event handler is set for the bubbling phase.
* element1.addEventListener('click',doSomething2,true) // capturing
* element2.addEventListener('click',doSomething2,true) // bubbling
* If the user clicks on element2 the following happens:
* 1. The click event starts in the capturing phase. The event looks if any ancestor element of element2 has a onclick event handler for the capturing phase.
* 2. The event finds one on element1. doSomething2() is executed.
* 3. The event travels down to the target itself, no more event handlers for the capturing phase are found. The event moves to its bubbling phase and executes doSomething(), which is registered to element2 for the bubbling phase.
* 4. The event travels upwards again and checks if any ancestor element of the target has an event handler for the bubbling phase. This is not the case, so nothing happens.
* Turning it off - But usually you want to turn all capturing and bubbling off to keep functions from interfering with each other.
* - window.event.cancelBubble = true
* - e.stopPropagation()
*/
// React questions: Features of react, virtual DOM, react hooks, custom hooks.
// What's shadow dom and virtual dom
/**
* What is the difference between ShadowDOM and VirtualDOM ? https://www.testim.io/blog/shadow-dom-vs-virtual-dom/
* ShadowDOM - is the concept that refers to the encapsulation of DOM elements and components
* - An API allowing developers to attach a “hidden” DOM to an element for encapsulation purposes
* - Encapsulate logic and presentation inside an element, protecting it from effects from the rest of the page
* - Browsers implements it
* VirtualDOM is virtual representation of DOM that optimizes the Updates to the RealDOM.
* - An in-memory representation of the DOM
* - Abstract the real DOM away, allowing for better performance and a more declarative style of coding
* - JavaScript libraries, such as React and Vue
*/
// build a search bar
// debouncing
const debounce1 = (fn, limit) => {
let timer = null;
return function () {
const ctx = this;
const args = arguments;
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(ctx, args);
}, limit);
}
}
const greet1 = () => console.log("hello greet");
const debouncedGreet1 = debounce1(greet1, 1000);
for (let i=0; i<10; i++) {
debouncedGreet1();
}
// throttling
const throttling = (fn, limit) => {
let flag = true;
return function () {
if (flag) {
let ctx = this;
let args = arguments;
fn.apply(ctx, args);
flag = false;
setTimeout(() => {
flag = true;
}, limit);
}
}
}
// React lifecycle - https://www.educative.io/answers/what-are-lifecycle-methods-in-react
// Flux vs Redux - https://medium.com/@sidathasiri/flux-and-redux-f6c9560997d7
// Redux toolkit - https://redux-toolkit.js.org/tutorials/quick-start