⏱ 0:00est. 29 min
Practice Jan 2024
// IIFE
const greet = (function (name) {
return `Hi, ${name}`;
})("Nishant");
console.log(greet);
// IIFE
(function (name) {
console.log(name);
})('Testing IIFE');
// --
// Perfect
{
name: "Nishant"
}
// --
// Perfect JS Code
("I'm a string");
// --
// async/await
async function f() {
return 1;
}
// Keyword async means the function will always return a promise
console.log(f()); // Promise { 1 }
console.log(f().then((result) => console.log(result))); // 1;
// following function is same as function f but it will resolve the promise
async function f1() {
return Promise.resolve(1);
}
console.log(f1()); // 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 is settled and returned 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() {
const startTime = new Date().getTime();
console.log('start', startTime);
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve(`done, ${new Date().getTime()} || diff ${new Date().getTime()-startTime}`), 1000);
})
const result = await promise; // wait until the promise is resolved
console.log(result); // done
}
f2();
async function delay() {
// wait 3 seconds
await new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
}
console.log(delay().then(() => console.log('done delay')));
// 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(); // <-- uncomment and try to run this, it will break the execution
f3().catch(err => console.error(err));
// fake fetch
async function fakeFetch(url) {
let p = new Promise((resolve, reject) => {
setTimeout(() => resolve(url), 1000);
})
let response = await p;
return response;
}
console.log(fakeFetch('url1').then((response) => console.log(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'),fakeFetch('url2')]);
console.log(result);
}
console.log(f4());
// call async from non-async
// we have a regular function called f5.
// how can we call the async function wait() and use it's result inside f5;
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(result => console.log(result)); // shows 10 after 1 second
}
f5();
// --
/**
* Promise
* Sample:
* let promise = new Promise((resolve, reject) => {
* // executor (the producing code)
* })
*/
// internal properties
// - state -- internally pending, changes to fulfilled when resolved is called or rejected when reject is called
// - result -- initially undefined, then changes to value of the resolve(value) called or error when reject(error) is called
// Example of fulfilled promise
let promiseFulfilled = new Promise((resolve, reject) => {
// this function is executed automatically when the promise is constructed
// after 1 second signal that the job is done with the result "done"
setTimeout(() => resolve("'promiseFulfilled' Done!", 1000));
});
promiseFulfilled.then(
(result) => console.log(result),
(error) => console.error(error)
);
// Example of the rejected state
let promiseRejected = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error("Rejected state test!")), 1000);
})
promiseRejected.then(
(result) => console.log(result),
(error) => console.error(error)
);
// promiseRejected.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!"), 1000);
})
.finally(() => console.log("Promise ready"))
.then((result) => console.log(result))
// output
// 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: "35",
}
function callMe() {
console.log(`Hi my name is ${this.name} and age is ${this.age} my city is ${arguments[0]}, and state is ${arguments[1]}`)
}
const call = callMe.bind(basic, "Delhi");
call('DL'); // // Hi my name is Nishant and my age is 35 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);
}
f7() // window
let user1 = {
g: f7.bind(null)
}
user1.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
// Polyfill of bind
Function.prototype.bindCustom = function (ctx, ...args1) {
let fn = this;
return function(...args2) {
fn.apply(ctx, [...args1, ...args2]);
}
}
let callWithCustomBind = PersonTest.bindCustom(personTestObj);
callWithCustomBind(); // 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-1-i]] = [arrToReverse2[arrToReverse2.length-1-i], arrToReverse2[i]]
}
console.log('arrToReverse2', arrToReverse2);
// Array.reduce
let nums = [1,2,3,4,5]
let sum = nums.reduce((acc, num) => {return acc+num}, 0);
console.log('sum', sum);
// closure
function greet1(whattosay) {
return function(name) {
console.log(whattosay, name);
}
}
greet1('Hi,')('Nishant');
// Object deep copy
const obj = {
a: 1,
b: "hello",
c: {
d: "world"
},
e: {
f: {
g: 100
}
}
};
const clonedCopy = JSON.parse(JSON.stringify(obj));
clonedCopy.a = 2;
console.log('originalObject', obj);
console.log('clonedCopy', clonedCopy);
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;
}
const clonedCopy1 = cloneObj(obj);
clonedCopy1.a = 3;
console.log('originalObject', obj);
console.log('clonedCopy1', clonedCopy1);
function debounce(fn, limit) {
let timer = null
return function() {
const ctx = this;
const args = arguments;
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(ctx, args);
}, limit);
}
}
const greet3 = () => console.log('Hello World! from debouncedGreet')
const debouncedGreet = debounce(greet3, 3000)
for (let i=0; i<10; i++) {
debouncedGreet();
}
function throttle (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)
}
}
}
function sumWithThrottle(x) {
console.log('sumWithThrottle', x+2);
}
const doSum1 = sumWithThrottle(500);
console.log('start')
throttle(doSum1, 1)
console.log('--1')
throttle(doSum1, 1)
console.log('--2')
throttle(doSum1, 1)
throttle(doSum1, 1)
console.log('--3')
throttle(doSum1, 1)
console.log('--4')
console.log('--2')
throttle(doSum1, 1)
console.log('--3')
throttle(doSum1, 1)
console.log('--4')
console.log('--2')
throttle(doSum1, 1)
console.log('--3')
throttle(doSum1, 1)
console.log('--4')
throttle(doSum1, 1)
console.log('--4')
console.log('--2')
throttle(doSum1, 1)
console.log('--3')
throttle(doSum1, 1)
console.log('--4')
console.log('--2')
throttle(doSum1, 1)
console.log('--3')
throttle(doSum1, 1)
console.log('--4')
throttle(doSum1, 1)
throttle(doSum1, 1)
throttle(doSum1, 1)
throttle(doSum1, 1)
throttle(doSum1, 1)
throttle(doSum1, 1)
throttle(doSum1, 1)
throttle(doSum1, 1)
throttle(doSum1, 1)
throttle(doSum1, 1)
throttle(doSum1, 1)
throttle(doSum1, 1)
throttle(doSum1, 1)
throttle(doSum1, 1)
throttle(doSum1, 1)
throttle(doSum1,0)
console.log('end')
// 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 d = "hi";
function b() {
console.log(a); // "undefined"
// console.log(d); // ReferenceError: Cannot access 'c' before initialization, program will break here
var a = "hello inner"
let d = "h1 inner"
console.log("called b!"); // called b
console.log(a); // hello inner
console.log(d); // hi inner
}
b();
var myVar = 2;
// Scope chain
function a1 () {
console.log(myVar); // undefined
var myVar = 3;
function b() {
console.log(myVar); // 3
}
b();
}
a1()
// Scope chain
var myVar = 1;
function a2() {
function b() {
console.log(myVar); // 1
}
b();
}
a2()
{
// Let, Const are hoisted differently. They are in temporal dead zone
// console.log(anew); // ReferenceError: Cannot access 'anew' before initialization
// - anew 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('bnew', bnew); // undefined
// - b is attached to global object
// allocated memory, hoising
let anew = "1";
var bnew = "2";
}
/*
{
var anew = "2";
let anew = "1";
console.log(anew); //Reference Error, Identifier 'a' has already been declared
}
*/
// --
// const a; // Syntax Error: Missing initializer in const declaration
// a = 100;
// console.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 multiply2 = multiply.bind(this, 2);
console.log(multiply2(3)); // 6
// Currying with closure
let multiplyWithClosure = function(x) {
return function(y) {
return x*y;
}
}
let multiply3 = multiplyWithClosure(3);
console.log(multiply3(2)); // 6
function sumWithClosure(a) {
return function (b) {
if (b) {
return sumWithClosure(b+a);
}
return a;
}
}
console.log('sumWithClosure(1)(2)(3)()', sumWithClosure(1)(2)(3)());