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