Modern Js Flashcards
Clone an object
Use Object.assign()
for shallow clone
const car = { color:'red' } const secondCar = Object.assign({}, car)
structuredClone(obj)
this
keyword
this
refers to the object that is currently executing the code.
The value of this
depends on how a function is called:
When a function is called as a method of an object, this
refers to the object itself.
When a function is called as a standalone function, this
refers to the global object (in non-strict mode) or undefined (in strict mode).
When a function is called using the new
keyword to create an instance of an object (constructor invocation), this refers to the newly created instance.
When a function is called using the call
, apply
, or bind
methods, this is explicitly set to a specified value.
Arrow functions do not have their own this context; they inherit this
from the enclosing lexical context.
call
, apply
, bind
-
call
method is used to invoke a function with specified this
const obj = { name: 'John' }; function greet(message) { console.log(`${message}, ${this.name}`); } greet.call(obj, 'Hello'); // Output: Hello, John
- apply method is similar to call but takes arguments as array
const obj = { name: 'John' }; function greet(message) { console.log(`${message}, ${this.name}`); } greet.apply(obj, ['Hello']); // Output: Hello, John
- bind method creates a new function with this set
const obj1 = { name: 'John' }; const obj2 = { name: 'Alice' }; function greet(message) { console.log(`${message}, ${this.name}`); } const greetJohn = greet.bind(obj1); const greetAlice = greet.bind(obj2); greetJohn('Hello'); // Output: Hello, John greetAlice('Hi'); // Output: Hi, Alice
Object.entries
Object.entries
returns an iterator with array of key value pairs
for(const [key, val] of Object.entries(car)){ console.log(key, val); }
Spread and rest
- spread operator expands array, object
let person = { name : "Alberto", surname: "Montalesi", age: 25, } let clone = {...person};
const name = ["Jon", "Paul", "Jones"]; function greet(first, last) { console.log(`Hello ${first} ${last}`); } greet(...name);
- rest operator condenses multiple elements into single
const runners = ["Tom", "Paul", "Mark", "Luke"]; const [,,...losers] = runners; console.log(...losers); // Mark Luke
Promise
A Promise is an object representing the eventual completion or failure of an asynchronous operation.
const myPromise = new Promise((resolve, reject) => { // your code goes here });
Promise.all
.race
.any
Hoisting
variables declared with var and functions are hoisted on the top of the scope. Only declarations are hoisted not values assigned. let and const are hoisted but are not accessible as they are in dead temporal zone
Closures
all functions are closures in JavaScript.
a closure is a function that can access the variables from another function’s scope. This is possible by creating nested functions. The enclosing/outer function will, however, not have access to the inner scope.
Each function stores it’s inner lexical environment and outer lexical environment as well.
Closure happens when a function is declared not when called
for(let i=0; i<3;i++){ setTimeout(()=>{ console.log(i) }, 500) }
this will print 0 1 2, with var it will print 3 3 3
Can we use multiple awaits in same line
Yes
num * await x * await y;
Output of the code
const array = [5, 11, 18, 25]; for (var i = 0; i < array.length; i++) { setTimeout(function() { console.log('Element: ' + array[i] + ', at index: ' + i); }, 3000); }
Element: undefined, at index: 4
Element: undefined, at index: 4
Element: undefined, at index: 4
Element: undefined, at index: 4
as array[4] is undefined and i is 4 outside the loop
Correct way
const array = [5, 11, 18, 25]; for (var i = 0; i < array.length; i++) { setTimeout(function (j) { console.log('Element: ' + array[j] + ', at index: ' + j); }, 3000, i); }
or
use let
to declare i
instead of var
Return nth cat
function returnNthCat(n){ const state = { cats : [ {catId : 1 , name : "tom"}, {catId : 2 , name : "tiggy"}, {catId : 3 , name : "leo"}, {catId : 4 , name : "nixie"} ], curpage : 3 } }
function returnNthCat(n){ const state = { cats : [ {catId : 1 , name : "tom"}, {catId : 2 , name : "tiggy"}, {catId : 3 , name : "leo"}, {catId : 4 , name : "nixie"} ], curpage : 3 } const {cats: {[n]: {name:cat}}} = state; return cat; }
What is the use of callstack, event queue and event loop
- call stack is used to keep track of all the function calls
- event queue is keep track of any async api calls or async activity. When callstack encounters any async activity it pops that and moves that to event queue.
- microtask queue
- dom manipulations
- The event loop has the task of checking both the call stack and the task queue continuously. When it sees that the call stack is done executing all the commands and is empty, it pops the commands from the task queue and pushes them into the call stack for execution. Then it runs microtask queue and dom manipulations
- promise callbacks get higher priority that event callbacks and timers
use chunking to split long tasks to smaller ones
What is event bubbling, capturing and target
- event bubbling - the event bubbles from the button/tab click to the parent till the document. All the handlers from button to the document are called.
- event capturing phase calls the event handlers from document till the element/button
Event delegation
instead of adding a event listener on all child elements we can attach event to a parent element and in the listener find which child element was clicked. With this we dont need to add listener on each child element
Object.freeze()
, Object.seal()
Object.freeze()
- prevents modification to existing propertiesObject.seal()
- prevents addition and deletion of properties
Prototypal inheritance
Object.create
prototype.constructor
call(this)
function Human(name, age) { this.name = name; this.age = age; }; function Man(name,age) { Human.call(this, name, age); }; Man.prototype = Object.create(Human.prototype); Man.prototype.constructor = Man; function check(){ var obj = new Man("Tommy Tan",20); console.log(obj.name) console.log(obj instanceof Human) }
What are higher order functions
Higher-Order functions accept functions as parameters or return a function as an output
Currying
The process of transforming a function to treat its parameters as a sequence of individual function calls that each take one parameter. For example, func(a, b, c) would become func(a)(b)(c).
Currying is achieved by creating functions that return other functions, taking advantage of closures. For example, a curried sum function would look like this:
function curriedSum(a) {
return function(b) {
return a + b;
};
}
This could then be used to create partial versions of this function, for example an “add four” function:
const addFour = curriedSum(4);
addFour(10); // 14
Arrow function and normal function difference
Do not have this
Do not have arguments
Can’t be called with super
Don’t have super
async programming with setTimeout
// Function that returns a promise which resolves after the specified delay function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // Asynchronous function using async/await async function performAsyncOperation() { console.log('Starting async operation...'); await delay(3000); // Waits for 3 seconds console.log('Async operation complete!'); } // Function to be used as a callback function callbackExample() { console.log('This is a callback example executed after 2 seconds'); } // Using setTimeout with a callback setTimeout(callbackExample, 2000); // Execute the asynchronous function performAsyncOperation();
cookie
// to set the cookie value, cookie values get added automatically one after another with ; document.cookie='name=harsh'; // setting this will delete the cookie document.cookie='name=harsh; max-age=0';
Web socket
// Create a new WebSocket connection const socket = new WebSocket('ws://localhost:8080', token); // Handle connection open event socket.addEventListener('open', function (event) { console.log('Connected to the WebSocket server'); socket.send('Hello Server!'); }); // Handle messages received from the server socket.addEventListener('message', function (event) { console.log('Message from server:', event.data); }); // Handle connection close event socket.addEventListener('close', function (event) { console.log('Disconnected from the WebSocket server'); }); // Send a message to the server when the button is clicked
other events:
close
error
Web components
Custom elements – to define custom HTML elements.
Shadow DOM – to create an internal DOM for the component, hidden from the others.
CSS Scoping – to declare styles that only apply inside the Shadow DOM of the component.
Event retargeting and other minor stuff to make custom components better fit the development.
class MyElement extends HTMLElement { constructor() { super(); // element created } connectedCallback() { // browser calls this method when the element is added to the document // (can be called many times if an element is repeatedly added/removed) } disconnectedCallback() { // browser calls this method when the element is removed from the document // (can be called many times if an element is repeatedly added/removed) } static get observedAttributes() { return [/* array of attribute names to monitor for changes */]; } attributeChangedCallback(name, oldValue, newValue) { // called when one of attributes listed above is modified } adoptedCallback() { // called when the element is moved to a new document // (happens in document.adoptNode, very rarely used) } // there can be other element methods and properties }
// let the browser know that <my-element> is served by our new class customElements.define("my-element", MyElement);
Customise built in components
<script> // The button that says "hello" on click class HelloButton extends HTMLButtonElement { constructor() { super(); this.addEventListener('click', () => alert("Hello!")); } } customElements.define('hello-button', HelloButton, {extends: 'button'}); </script> <button is="hello-button">Click me</button> <button is="hello-button" disabled>Disabled</button>
customElements.define('show-hello', class extends HTMLElement { connectedCallback() { const shadow = this.attachShadow({mode: 'open'}); shadow.innerHTML = `<p> Hello, ${this.getAttribute('name')} </p>`; } });
Cancellable promise
simple solution
function cancellablePromise(promise) { let rejectFn = null; const wrapper = new Promise((resolve, reject) => { rejectFn = reject; promise.then(resolve) .catch(reject) }); wrapper.cancel = function() { rejectFn({ isCancelled: true }); } return wrapper; } const pro = cancellablePromise(new Promise((res, rej) => { res(1); })); pro.then(console.log) pro.catch(console.log) /* pro.cancel(); */
correct solution
class CancellablePromise extends Promise { constructor(executor) { let _reject; super((resolve, reject) => { _reject = reject; executor(resolve, reject); }); this._reject = _reject; } cancel() { this._reject('Promise cancelled'); } } // Usage example: const longRunningTask = new CancellablePromise((resolve, reject) => { const timerId = setTimeout(() => { resolve('Task completed'); }, 5000); }); // To cancel the promise: longRunningTask.cancel(); // To use the promise: longRunningTask .then(result => console.log(result)) .catch(error => console.error(error));