Deep Copy vs Shallow Copy
Shallow Copy
A shallow copy creates a new object with a new reference, but the properties of the new object refer to the same memory locations as the properties of the original object.
JavaScript Code Example:
const original = { a: 1, b: { c: 2 } };
const shallowCopy = { ...original };
shallowCopy.b.c = 3;
console.log(original.b.c); // Output: 3 (Because the inner object is shared)
Deep Copy
A deep copy creates a new object and recursively copies all objects and arrays, ensuring no references to the original object.
JavaScript Code Example:
const original = { a: 1, b: { c: 2 } };
const deepCopy = JSON.parse(JSON.stringify(original));
deepCopy.b.c = 3;
console.log(original.b.c); // Output: 2 (The inner object is not shared)
Deep Copy using a Custom Function
function deepCopy(obj) {
return JSON.parse(JSON.stringify(obj));
}
const original = { a: 1, b: { c: 2 } };
const copy = deepCopy(original);
copy.b.c = 3;
console.log(original.b.c); // Output: 2
Search Key-Value Pairs in Nested Object with Recursions
JavaScript Code Example:
function findValue(obj, keyToFind) {
let result = null;
function search(obj) {
for (let key in obj) {
if (key === keyToFind) {
result = obj[key];
return;
}
if (typeof obj[key] === 'object' && obj[key] !== null) {
search(obj[key]);
}
}
}
search(obj);
return result;
}
const data = { a: { b: { c: 1 } } };
console.log(findValue(data, 'c')); // Output: 1
What is Currying Function?
Currying is a technique where a function returns another function that accepts one argument at a time.
JavaScript Code Example:
function multiply(a) {
return function(b) {
return function(c) {
return a * b * c;
};
};
}
console.log(multiply(3)(2)(6)); // Output: 36
Prototype Inheritance and Keeping Child Prototype Intact
JavaScript Code Example:
function Parent() {
this.parentProperty = 'parent';
}
Parent.prototype.parentMethod = function() {
console.log('Parent method');
};
function Child() {
Parent.call(this);
this.childProperty = 'child';
}
// Set up inheritance
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
Child.prototype.childMethod = function() {
console.log('Child method');
};
const child = new Child();
child.parentMethod(); // Output: 'Parent method'
child.childMethod(); // Output: 'Child method'
Using Object.create
ensures that the Child.prototype
object correctly inherits from Parent.prototype
.
Event Loop in Detail
The Event Loop is a mechanism that allows JavaScript to perform non-blocking operations by using a single-threaded model. It handles callbacks, promises, and other asynchronous operations.
Steps of the Event Loop:
- Execute Synchronous Code: Execute all the code that is present in the execution context.
- Check the Callbacks Queue: After executing the code, the event loop checks the callback queue (task queue) to see if there are any functions to run.
- Process the Callbacks: Process the functions from the callback queue.
- Check for Microtasks: Before moving to the next event loop iteration, it processes microtasks (promises).
Output Question Based on Event Loop
console.log(1);
setTimeout(() => { console.log(2) }, 0);
Promise.resolve().then(() => console.log(3));
Promise.resolve().then(() => setTimeout(() => { console.log(4) }, 0));
Promise.resolve().then(() => console.log(5));
setTimeout(() => { console.log(6) }, 0);
console.log(7);
Output:
- Synchronous Code:
console.log(1)
logs1
- Microtasks:
Promise.resolve().then(() => console.log(3))
logs3
- Microtasks:
Promise.resolve().then(() => console.log(5))
logs5
- Microtasks:
Promise.resolve().then(() => setTimeout(() => { console.log(4) }, 0))
is scheduled to run after the current microtasks - Timeouts:
setTimeout(() => { console.log(2) }, 0)
andsetTimeout(() => { console.log(6) }, 0)
are scheduled to run in the next event loop iteration - Synchronous Code:
console.log(7)
logs7
- Next Microtasks: Logs
4
from thesetTimeout
wrapped in aPromise
resolved - Timeouts: Logs
2
and6
from thesetTimeout
calls
Output Order:
1
7
3
5
2
6
4
React
Call Demo API and Filter List as We Type in Input Box
JavaScript Code Example (React):
import React, { useState, useEffect } from 'react';
import axios from 'axios';
const DemoComponent = () => {
const [data, setData] = useState([]);
const [query, setQuery] = useState('');
const [filteredData, setFilteredData] = useState([]);
useEffect(() => {
async function fetchData() {
const result = await axios('https://api.example.com/data');
setData(result.data);
}
fetchData();
}, []);
useEffect(() => {
setFilteredData(data.filter(item => item.name.toLowerCase().includes(query.toLowerCase())));
}, [query, data]);
return (
<div>
<input type="text" value={query} onChange={e => setQuery(e.target.value)} />
<ul>
{filteredData.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</div>
);
};
export default DemoComponent;
How to Optimize React and Above React Project
- Use Memoization: Use
React.memo
,useMemo
, anduseCallback
to prevent unnecessary re-renders. - Code Splitting: Dynamically import components to split code and improve load times.
- Virtualization: Use libraries like
react-window
for rendering large lists efficiently. - Avoid Inline Functions: Move functions out of render methods to prevent creating new function instances.
- Optimize Dependencies: Ensure that
useEffect
anduseCallback
dependencies are well managed to avoid excessive re-renders.
JavaScript
How to Access DOM Elements in JS
JavaScript Code Example:
const elementById = document.getElementById('myId');
const elementByClassName = document.getElementsByClassName('myClass')[0];
const elementByTagName = document.getElementsByTagName('div')[0];
const elementByQuerySelector = document.querySelector('.myClass');
const elementsByQuerySelectorAll = document.querySelectorAll('.myClass');
What is Iframe
An <iframe>
element allows you to embed another HTML document within the current document.
Example HTML Code:
<iframe src="https://www.example.com" width="600" height="400"></iframe>
How to Access an Element from Iframe
JavaScript Code Example:
const iframe = document.getElementById('myIframe');
const iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
const elementInIframe = iframeDocument.getElementById('elementId');
What is the Difference Between Window and Document
- Window: Represents the browser window or tab, and has properties like
alert
,open
, andlocation
. - Document: Represents the HTML content of the window and has properties like
getElementById
,querySelector
, andcreateElement
.
What are Timers in JS
Timers are functions that allow you to execute code after a delay.
setTimeout(callback, delay)
: Executescallback
afterdelay
milliseconds.setInterval(callback, interval)
: Repeatedly executescallback
everyinterval
milliseconds.
What is Promise in JS
A Promise
represents a value that may be available now, or in the future, or never. It is a way to handle asynchronous operations.
JavaScript Code Example:
const promise = new Promise((resolve, reject) => {
// Asynchronous operation
if (true) {
resolve('Success');
} else {
reject('Error');
}
});
promise.then(result => console.log(result)).catch(error => console.log(error));
Certainly! Let’s dive into the details of deep cloning limitations using JSON.parse(JSON.stringify(obj))
and explore the concept of closures in JavaScript with an example.
Limitations of Deep Cloning Using JSON.parse(JSON.stringify(obj))
The JSON.parse(JSON.stringify(obj))
method is a common approach for deep cloning objects in JavaScript, but it has several limitations:
**1. *Date
Objects are Lost*:
When you use JSON.stringify
, Date
objects are converted to strings. The resulting Date
information is lost after parsing.
Example:
const original = { date: new Date() };
const clone = JSON.parse(JSON.stringify(original));
console.log(original.date); // Output: Date object
console.log(clone.date); // Output: String representation of the Date object
console.log(clone.date instanceof Date); // Output: false
**2. *Functions
are Not Cloned*:
Functions cannot be cloned using JSON.stringify
because functions are not supported in JSON format.
Example:
const original = { func: () => console.log('Hello') };
const clone = JSON.parse(JSON.stringify(original));
console.log(clone.func); // Output: undefined
**3. *undefined
, Infinity
, and NaN
Values are Ignored*:
These values are not represented in JSON, so they are lost in the cloning process.
Example:
const original = { a: undefined, b: Infinity, c: NaN };
const clone = JSON.parse(JSON.stringify(original));
console.log(clone.a); // Output: undefined
console.log(clone.b); // Output: null (because Infinity is not represented in JSON)
console.log(clone.c); // Output: null (because NaN is not represented in JSON)
**4. *RegExp
Objects are Lost*:
Regular expressions are not preserved through JSON.stringify
.
Example:
const original = { regex: /test/ };
const clone = JSON.parse(JSON.stringify(original));
console.log(clone.regex); // Output: undefined
console.log(clone.regex instanceof RegExp); // Output: false
**5. *Symbol
Properties are Ignored*:
Properties keyed by Symbol
are not included in the JSON representation.
Example:
const sym = Symbol('mySymbol');
const original = { [sym]: 'value' };
const clone = JSON.parse(JSON.stringify(original));
console.log(clone[sym]); // Output: undefined
**6. *Circular References are Not Supported*:
JSON.stringify
cannot handle objects with circular references.
Example:
const a = {};
a.b = a;
try {
const clone = JSON.parse(JSON.stringify(a));
} catch (error) {
console.error(error); // Output: TypeError: Converting circular structure to JSON
}
**7. *Prototype Chain is Not Cloned*:
Only the properties of the object are cloned, not its prototype chain.
Example:
function MyClass() {
this.name = 'example';
}
MyClass.prototype.greet = function() { return 'Hello'; };
const original = new MyClass();
const clone = JSON.parse(JSON.stringify(original));
console.log(clone.greet); // Output: undefined
What is the Usage of Closure? Show an Example
What is a Closure?
A closure is a feature in JavaScript where an inner function retains access to the variables of its outer function even after the outer function has finished executing. This allows for the creation of private variables and functions, and it supports data encapsulation and function factories.
Usage of Closures
- Data Encapsulation: Protect data from being accessed directly from outside the function.
- Function Factories: Create functions with specific configurations.
- Maintaining State: Keep track of state across function calls.
Example of a Closure
1. Data Encapsulation Example:
function createCounter() {
let count = 0; // `count` is a private variable
return function() {
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // Output: 1
console.log(counter()); // Output: 2
console.log(counter()); // Output: 3
In this example, count
is a private variable that is only accessible through the returned inner function.
2. Function Factory Example:
function multiplyBy(factor) {
return function(num) {
return num * factor;
};
}
const double = multiplyBy(2);
console.log(double(5)); // Output: 10
const triple = multiplyBy(3);
console.log(triple(5)); // Output: 15
Here, multiplyBy
is a function factory that creates functions for multiplying numbers by a specific factor.
3. Maintaining State Example:
function createCounter(initialValue) {
let count = initialValue;
return {
increment() {
count++;
return count;
},
decrement() {
count--;
return count;
},
getValue() {
return count;
}
};
}
const myCounter = createCounter(10);
console.log(myCounter.getValue()); // Output: 10
console.log(myCounter.increment()); // Output: 11
console.log(myCounter.decrement()); // Output: 10
In this example, myCounter
maintains the state of the count variable through multiple function calls.
Summary Table of Closures
Feature | Description | Example |
---|---|---|
Data Encapsulation | Hide private data from the outside world | const counter = createCounter(); |
Function Factory | Generate functions with customized behavior | const double = multiplyBy(2); |
Maintaining State | Preserve state between function calls | const myCounter = createCounter(10); |