JavaScript FAQs
1. Explain the concept of "hoisting" in JavaScript
Hoisting describes the behavior of variable declarations in JavaScript.
Hoisting describes the behavior of variable declarations in JavaScript.
Only the declaration is hoisted, not the initialization.
Variables with let, const, and class, these are also hoisted but not initialized.
Accessing them before declaration results in a ReferenceError.
2. What are the differences between JavaScript variables created using let, var or const?
Scope:
var**: Function-scoped or globally scoped.
let and const**: Block-scoped (only accessible within the nearest set of curly braces).
Initialization:
var and let**: Can be declared without an initial value.
const**: Must be initialized at the time of declaration.
Redeclaration:
var**: Allows redeclaration.
let and const**: Do not allow redeclaration.
Reassignment:
var and let**: Allow reassignment.
const**: Does not allow reassignment.
Accessing before declaration:
var**: Variables are hoisted and initialized to undefined.
let and const**: Variables are hoisted but not initialized, causing a ReferenceError if accessed before declaration.
3. What is the difference between == and === in JavaScript?
Equality Operator (==):
Performs type coercion, converting values to a common type before comparison.
Can yield unintuitive results due to type conversion.
Strict Equality Operator (===):
Does not perform type coercion.
Both value and type must be the same for the comparison to return true.
Best Practices:
Use == only when comparing against null or undefined for convenience.
Prefer === for all other comparisons to avoid pitfalls of type coercion and ensure both value and type are the same.
4. What is the event loop in JavaScript?
The event loop is crucial for handling asynchronous operations in JavaScript, allowing single-threaded execution without blocking.
Components
1. Call Stack:
Tracks function execution in LIFO order.
Functions are added and removed as they are called and complete.
2. Web APIs/Node.js APIs:
Handle asynchronous tasks (setTimeout(), HTTP requests) on separate threads.
3. Task Queue (Macrotask Queue):
Holds tasks like setTimeout(), setInterval(), and UI events.
4. Microtask Queue:
Contains high-priority tasks (e.g., Promise callbacks).
Executes after the current script but before the next macrotask.
Execution Order
1. Script Execution:
- Synchronous tasks are placed on the call stack.
2. Asynchronous Operations:
- Offloaded to Web APIs/Node.js APIs.
3. Task Completion:
- Completed tasks are queued in the appropriate task or microtask queue.
4. Event Loop Monitoring:
- Executes tasks from the call stack.
- When the stack is empty:
- Processes the microtask queue until empty.
- Processes one macrotask, then checks the microtask queue again.
- Repeats indefinitely.
console.log('Start');
setTimeout(() => {
console.log('Timeout 1');
}, 0);
Promise.resolve().then(() => {
console.log('Promise 1');
});
setTimeout(() => {
console.log('Timeout 2');
}, 0);
console.log('End');
Console Output:
Start
End
Promise 1
Timeout 1
Timeout 2
Explanation:
Start and End are logged first (synchronous).
Promise 1 is logged next (microtask).
Timeout 1 and Timeout 2 are logged last (macrotasks).
Understanding the event loop helps write efficient, non-blocking JavaScript code.
5. Explain event delegation in JavaScript
Event delegation is an efficient way to handle events on multiple child elements by attaching a single event listener to a common parent element.
This is useful for managing events on many similar elements, like list items.
How Event Delegation Works
1. Attach Listener to Ancestor:
Attach one listener to a parent element instead of individual listeners on each child.
2. Event Bubbling:
When an event occurs on a child, it bubbles up to the parent, where the listener can handle it.
3. Determine the Target:
Use event.target to identify the actual element that triggered the event.
4. Perform Action:
Execute actions based on the target element.
Benefits of Event Delegation
Efficiency: Fewer event listeners improve memory and performance.
Dynamic Elements: Automatically handles new or removed child elements.
// HTML:
// <ul id="item-list">
// <li>Item 1</li>
// <li>Item 2</li>
// <li>Item 3</li>
// </ul>
const itemList = document.getElementById('item-list');
itemList.addEventListener('click', (event) => {
if (event.target.tagName === 'LI') {
console.log(`Clicked on ${event.target.textContent}`);
}
});
A single click listener on <ul> handles clicks on any <li> due to event bubbling.
Use Cases
1. Dynamic Content:
const buttonContainer = document.getElementById('button-container');
const addButton = document.getElementById('add-button');
buttonContainer.addEventListener('click', (event) => {
if (event.target.tagName === 'BUTTON') {
console.log(`Clicked on ${event.target.textContent}`);
}
});
addButton.addEventListener('click', () => {
const newButton = document.createElement('button');
newButton.textContent = `Button ${buttonContainer.children.length + 1}`;
buttonContainer.appendChild(newButton);
});
2. Simplifying Code:
const userForm = document.getElementById('user-form');
userForm.addEventListener('input', (event) => {
const { name, value } = event.target;
console.log(`Changed ${name}: ${value}`);
});
6. Explain how this works in JavaScript
The this keyword in JavaScript can be quite confusing as its value depends on how a function is called.
Here are the main rules that determine the value of this:
1. Using the new Keyword
Creates a new object and sets this to that object.
function Person(name) {
this.name = name;
}
const person = new Person('Alice');
console.log(person.name); // 'Alice
2. Using apply, call, or bind
Explicitly sets this to a specified object.
javascriptCopy code
function greet() {
console.log(this.name);
}
const person = { name: 'Alice' };
greet.call(person); // 'Alice'
3. Method Call
this is bound to the object the method is called on.
const obj = {
name: 'Alice',
greet: function () {
console.log(this.name);
},
};
obj.greet(); // 'Alice'
4. Free Function Invocation
In non-strict mode, defaults to the global object (window in browsers); in strict mode, defaults to undefined.
function greet() {
console.log(this); // global object or undefined
}
greet();
5. Arrow Functions (ES6):
Inherit this from their lexical enclosing scope.
const obj = {
name: 'Alice',
greet: () => {
console.log(this.name); // `this` refers to the enclosing scope
},
};
obj.greet(); // undefined
ES2015 (ES6) and this
ES2015 introduced arrow functions which capture this from their lexical scope. This can simplify code but requires caution when integrating with libraries expecting traditional function context.
Example:
function Timer() {
this.seconds = 0;
setInterval(() => {
this.seconds++; // `this` refers to the Timer instance
console.log(this.seconds);
}, 1000);
}
const timer = new Timer();
7. Describe the difference between a cookie, sessionStorage and localStorage.
Cookies, localStorage, and sessionStorage are key client-side storage mechanisms in web applications, each serving distinct purposes:
Cookies:
Purpose: Stores small data pieces sent to the server with HTTP requests.
Capacity: Limited to around 4KB per domain.
Lifespan: Can have expiration dates; session cookies are cleared when the browser closes.
Access: Domain-specific; accessible across pages and subdomains.
Security: Supports HttpOnly and Secure flags to restrict JavaScript access and ensure HTTPS transmission.
Ex:
// Set a cookie with an expiry
document.cookie = 'auth_token=abc123def; expires=Fri, 31 Dec 2024 23:59:59 GMT; path=/';
// Read all cookies (no direct method for specific cookies)
console.log(document.cookie);
// Delete a cookie
document.cookie = 'auth_token=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/';
localStorage
Purpose: Stores data persistently on the client-side.
Capacity: Around 5MB per origin.
Lifespan: Data remains until explicitly cleared.
Access: Available across all tabs and windows within the same origin.
Security: All JavaScript on the page can access localStorage values.
Ex:
// Set an item in localStorage
localStorage.setItem('key', 'value');
// Get an item from localStorage
console.log(localStorage.getItem('key'));
// Remove an item from localStorage
localStorage.removeItem('key');
// Clear all data in localStorage
localStorage.clear();
sessionStorage:
Purpose: Stores session-specific data that persists until the browser or tab is closed.
Capacity: Similar to localStorage, around 5MB per origin.
Lifespan: Cleared when the tab or browser closes; reloading the page retains data.
Access: Limited to the current tab or window.
Security: All JavaScript on the page can access sessionStorage values.
Ex:
// Set an item in sessionStorage
sessionStorage.setItem('key', 'value');
// Get an item from sessionStorage
console.log(sessionStorage.getItem('key'));
// Remove an item from sessionStorage
sessionStorage.removeItem('key');
// Clear all data in sessionStorage
sessionStorage.clear();
8. Describe the difference between <script>, <script async> and <script defer>
<script> Tag:
- The <script> tag is used to include JavaScript in a web page.
- Behavior: HTML parsing halts while the script is fetched and executed immediately.
- Usage: Suitable for critical scripts required for initial page rendering.
<script async> Tag:
- Behavior: Downloads the script asynchronously while HTML parsing continues. Executes the script as soon as it's available, potentially before HTML parsing completes.
- Usage: Suitable for independent scripts like analytics or ads.
<script defer> Tag:
Behavior: Downloads the script asynchronously while HTML parsing proceeds. Executes the script after the HTML document is fully parsed but before DOMContentLoaded.
Usage: Ideal for scripts dependent on a fully-parsed DOM structure.
9. What's the difference between a variable that is: null, undefined or undeclared?
Undeclared: A variable that is not declared using var, let, or const will be created globally and can cause errors. Avoid them by using try/catch blocks to detect them.
undefined: A declared variable without an assigned value is undefined. Use === or typeof to check for undefined. Note that == will also return true for null.
null: A variable explicitly assigned null represents no value. Use === to check for null. Don't use == as it will also return true for undefined**.