1. Explain the concepts of call, apply, and bind in JavaScript. Provide examples.
Description: call, apply, and bind are methods used to change the this value in functions.
const person = { name: 'Alice' };
function greet(greeting) {
console.log(`${greeting}, ${this.name}!`);
}
greet.call(person, 'Hello'); // Output: Hello, Alice!
greet.apply(person, ['Hi']); // Output: Hi, Alice!
const greetBound = greet.bind(person);
greetBound('Hey'); // Output: Hey, Alice!
2. Explain the difference between let
, const
, and var
in JavaScript.
In JavaScript, let
, const
, and var
are used to declare variables. Each has different scoping rules and reassignment capabilities, making them suitable for different use cases.
1. var
:
var
was traditionally used to declare variables in JavaScript.- Variables declared with
var
are function-scoped, meaning they are only accessible within the function they are declared in. - Variables declared with
var
can be redeclared and updated.
function exampleVar() {
var x = 10;
if (true) {
var x = 20; // This reassigns the existing variable 'x'
console.log(x); // Output: 20
}
console.log(x); // Output: 20 (not 10)
}
2. let
:
- Introduced in ES6,
let
allows block-scoping of variables, making them accessible only within the block they are defined in (e.g., if, for, while blocks). - Variables declared with
let
can be reassigned but cannot be redeclared in the same scope.
function exampleLet() {
let y = 30;
if (true) {
let y = 40; // This creates a new block-scoped variable 'y'
console.log(y); // Output: 40
}
console.log(y); // Output: 30 (not affected by the inner 'y')
}
3. const
:
- Also introduced in ES6,
const
is used to declare constants whose values cannot be reassigned. - Variables declared with
const
are block-scoped likelet
. - A
const
variable must be assigned a value during declaration and cannot be left uninitialized.
function exampleConst() {
const z = 50;
// z = 60; // Error: Assignment to a constant variable
console.log(z); // Output: 50
}
In summary:
- Use
var
for traditional function-scoped variables (but it's recommended to uselet
andconst
in modern JavaScript). - Use
let
when you need to reassign a variable's value within the same block. - Use
const
when you want to define a constant value that should not be reassigned.
It's good practice to use let
and const
over var
for better scoping and to avoid potential issues related to hoisting and unintended variable reassignment.
3. What is a closure in JavaScript? Provide an example.
Answer:
function outer() {
const message = 'Hello';
function inner() {
console.log(message);
}
return inner;
}
const innerFunc = outer();
innerFunc(); // Output: 'Hello'
4. What is event delegation in JavaScript?
Answer: Event delegation is a technique where a single event listener is attached to a common ancestor, allowing events to be handled for multiple children.
5. What is the difference between ==
and ===
in JavaScript?
Answer: ==
checks for equality with type coercion, while ===
checks for strict equality without type coercion.
6. What is the purpose of the async
and await
keywords in JavaScript?
Answer: async
and await
are features introduced in ES2017 (ES8) that make working with asynchronous code more readable and easier to manage. They are built on top of promises.
1. async
:
async
is used to declare that a function will work with promises and may useawait
within its body.- It allows a function to return a promise implicitly.
- Functions marked with
async
always return a promise, even if you return a non-promise value.
async function asyncFunction() {
return 42; // Equivalent to returning Promise.resolve(42)
}
2. await
:
await
can only be used within anasync
function.- It is used to pause the execution of the function until a promise is resolved or rejected.
- It "awaits" the result of a promise and returns the resolved value or throws an error for a rejected promise.
async function fetchUserData() {
try {
const response = await fetch('https://api.example.com/user');
const data = await response.json();
return data;
} catch (error) {
console.error('Error:', error);
}
}
3. Difference from .then()
:
- While both
await
and.then()
handle asynchronous operations, the key difference lies in how they manage the flow of asynchronous code. .then()
is used with promises and is chaining-based, where each.then()
function returns a promise and allows you to chain further operations.await
, on the other hand, allows for more synchronous-like code withinasync
functions, making asynchronous code appear more linear and readable.
// Using .then()
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
// Using await
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
} catch (error) {
console.error('Error:', error);
}
}
In summary, async
and await
make asynchronous code look and behave more like synchronous code, enhancing readability and maintainability, especially when dealing with promises.
7. Explain what the this
keyword refers to in JavaScript.
Answer:
this
refers to the object on which a method is being called.
8. What is a promise in JavaScript? Provide an example of creating and using a promise.
Answer:
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Promise resolved!');
}, 2000);
});
myPromise.then((result) => {
console.log(result);
}).catch((error) => {
console.error(error);
});
9. What is a callback function in JavaScript? Provide an example.
Answer:
function fetchData(callback) {
setTimeout(() => {
callback('Data fetched!');
}, 2000);
}
fetchData((data) => {
console.log(data);
});
10. What is the difference between null
and undefined
in JavaScript?
Answer:
null
is an assignment value representing no value or no object, while undefined
is a primitive value automatically assigned to uninitialized variables.
11. What is event bubbling in JavaScript?
Answer: Event bubbling is the propagation of an event from the target element up to its parent and higher ancestors in the DOM tree.
12. What is event.preventDefault()? Provide an example of its usage.
Description: event.preventDefault() is used to prevent the default behavior of an event, such as form submission or link navigation.
Answer:
const submitButton = document.getElementById('submitButton');
submitButton.addEventListener('click', event => {
event.preventDefault(); // Prevents form submission
console.log('Form submission prevented.');
});
13. What are arrow functions in JavaScript? Provide an example.
Answer:
const add = (a, b) => a + b;
console.log(add(2, 3)); // Output: 5
14. What is the purpose of the localStorage
and sessionStorage
objects in JavaScript?
Answer:
They provide a way to store key-value pairs in a web browser, with localStorage
persisting even after the browser is closed and reopened, and sessionStorage
existing only for the duration of the page session.
15. Explain event handling in JavaScript and provide an example of attaching an event listener.
Answer:
const button = document.getElementById('myButton');
button.addEventListener('click', () => {
console.log('Button clicked!');
});
16. What is the difference between map()
and forEach()
array methods in JavaScript?
Answer: map()
returns a new array with the results of a function applied to each element, while forEach()
only iterates over the array and does not return a new array.
17. What is a RESTful API and how do you make a GET request using JavaScript?
Answer:
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
18. What is the purpose of the use strict
directive in JavaScript?
The "use strict" directive in JavaScript is used to enable a stricter interpretation of the code, catching common mistakes and preventing the use of certain error-prone features. When this directive is applied, the JavaScript engine enforces stricter rules for writing code.
1. Purpose:
- It helps in writing more reliable and maintainable code by identifying and disallowing potentially error-prone behavior.
- It prevents the accidental creation of global variables by enforcing block scope rules with
let
andconst
. - It disallows the use of certain language features that are deprecated or considered bad practice.
2. Example:
// Without "use strict"
function withoutStrict() {
variable = 10; // This will create a global variable accidentally
console.log(variable);
}
withoutStrict(); // Output: 10
// With "use strict"
function withStrict() {
'use strict';
variable = 20; // This will throw a ReferenceError
console.log(variable);
}
withStrict(); // Error: variable is not defined
In the first example without "use strict," variable
is mistakenly created as a global variable, which can lead to unexpected behavior and bugs in a larger codebase.
In the second example with "use strict," attempting to assign a value to variable
without declaring it with var
, let
, or const
will throw a ReferenceError
, indicating that variable
is not defined. This helps catch potential bugs and encourages better coding practices.
To enable "use strict" globally in a script, you can add it at the beginning of your JavaScript file or within a function. For modern JavaScript development, it's recommended to use "use strict" to enhance code quality and reduce the risk of errors.
19. Explain hoisting in JavaScript.
Answer:
- Hoisting is a JavaScript mechanism where variable and function declarations are moved to the top of their containing scope during the compile phase.
console.log(x); // Output: undefined
var x = 10;
console.log(x); // Output: 10
20. How do you handle errors in JavaScript? Provide an example of using a try...catch
block.
Answer:
try {
// Code that may throw an error
const result = 10 / 0;
console.log(result);
} catch (error) {
console.error('An error occurred:', error.message);
}
21. What are template literals in JavaScript? Provide an example.
Answer:
-
Template literals are a feature introduced in ES6 that allow for easier string interpolation and multi-line strings. They are enclosed by backticks (`) instead of single or double quotes.
const name = 'Alice'; const greeting = `Hello, ${name}!`; console.log(greeting); // Output: Hello, Alice!
22. Explain the concept of "prototypal inheritance" in JavaScript.
Answer:
-
Prototypal inheritance is a feature in JavaScript where objects can inherit properties and methods from other objects. This is achieved through the prototype chain.
const animal = { speak() { console.log('Animal speaks'); }, }; const dog = Object.create(animal); dog.speak(); // Output: Animal speaks
23. What are Promise.all() and Promise.race()? Provide examples of their usage.
Answer:
-
Promise.all() takes an array of promises and returns a single promise that resolves when all of the promises in the array have resolved, or rejects if any promise is rejected.
-
Promise.race() returns a promise that resolves or rejects as soon as one of the promises in the array resolves or rejects.
// Example of Promise.all Promise.all([ Promise.resolve(1), Promise.resolve(2), Promise.resolve(3), ]).then(values => { console.log(values); // Output: [1, 2, 3] }); // Example of Promise.race Promise.race([ new Promise((resolve) => setTimeout(() => resolve('First'), 1000)), new Promise((resolve) => setTimeout(() => resolve('Second'), 500)), ]).then(result => { console.log(result); // Output: 'Second' });
24. What are higher-order functions in JavaScript? Provide an example.
Answer:
- Higher-order functions are functions that take other functions as arguments or return functions as their result. This allows for more abstract and reusable code.
function createMultiplier(multiplier) {
return function(x) {
return x * multiplier;
};
}
const double = createMultiplier(2);
console.log(double(5)); // Output: 10
25. What is the difference between shallow copy and deep copy?
Answer:
- A shallow copy duplicates the top-level properties of an object. If the properties are references to other objects, the references are copied, not the actual objects.
- A deep copy creates a new object and recursively copies all properties and their values.
const original = { a: 1, b: { c: 2 } };
// Shallow copy
const shallowCopy = Object.assign({}, original);
shallowCopy.b.c = 3; // Changes 'c' in both objects
console.log(original.b.c); // Output: 3
// Deep copy
const deepCopy = JSON.parse(JSON.stringify(original));
deepCopy.b.c = 4; // Changes 'c' only in deepCopy
console.log(original.b.c); // Output: 3
26. What is the purpose of setTimeout and setInterval in JavaScript? Provide examples.
Answer:
- setTimeout is used to execute a function after a specified delay (in milliseconds).
- setInterval is used to repeatedly execute a function at specified intervals.
setTimeout(() => {
console.log('Executed after 1 second');
}, 1000);
let count = 0;
const intervalId = setInterval(() => {
console.log('Count:', count++);
if (count === 5) clearInterval(intervalId); // Stop after 5 counts
}, 1000);
27. What are the JavaScript data types?
Answer:
-
JavaScript has several data types, including:
-
Primitive Types:
- string: Represents text values.
- number: Represents numeric values.
- boolean: Represents true or false.
- null: Represents an intentional absence of any object value.
- undefined: Represents a variable that has been declared but not yet assigned a value.
- symbol: Represents a unique identifier (introduced in ES6).
- bigint: Represents integers with arbitrary precision (introduced in ES11).
-
Reference Types:
- object: Represents complex data structures like arrays and objects.
28. What is the difference between synchronous and asynchronous programming in JavaScript?
Answer:
- Synchronous programming executes code in a sequential manner, where each operation must complete before the next one starts.
- Asynchronous programming allows for operations to be executed independently of the main program flow, enabling code to run in the background while other operations continue.
// Synchronous example
console.log('First');
console.log('Second');
// Asynchronous example
setTimeout(() => {
console.log('Asynchronous operation');
}, 1000);
console.log('Third');
29. How can you check if a variable is an array in JavaScript?
Answer:
- You can use the Array.isArray() method to check if a variable is an array.
const arr = [1, 2, 3];
console.log(Array.isArray(arr)); // Output: true
const obj = {};
console.log(Array.isArray(obj)); // Output: false
30. What is the difference between static and dynamic typing in JavaScript?
Answer:
- Static typing requires variable types to be declared explicitly, enabling type checking at compile time (not supported in JavaScript).
- Dynamic typing allows variables to hold values of any type without explicit type declaration, enabling type checking at runtime.
31. What are the main differences between ES5 and ES6?
-
Variable Declarations ES5: Uses var (function-scoped). ES6: Introduces let and const (block-scoped).
-
Arrow Functions ES5: Regular functions with function. ES6: Arrow functions (() => ) with lexical this.
-
Template Literals ES5: String concatenation with +. ES6: Template literals using backticks for interpolation.
-
Destructuring Assignment ES5: Manual extraction of values. ES6: Simplified destructuring for arrays and objects.
-
Modules ES5: No native support; relies on libraries. ES6: Native import and export for modules.
-
Promises ES5: Callbacks for async operations. ES6: Promises for better async handling.
-
Iterators and Generators ES5: No support for iterators. ES6: Introduces iterators and generator functions.
32. How do you implement inheritance in JavaScript?
Inheritance can be implemented using prototypes or the class syntax introduced in ES6.
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(`${this.name} makes a noise.`);
};
function Dog(name) {
Animal.call(this, name);
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.bark = function() {
console.log(`${this.name} barks.`);
};
33. What is a memory leak in JavaScript, and how can you avoid it?
- A memory leak occurs when memory that is no longer needed is not released. Common causes include global variables, closures, and forgotten timers. You can avoid memory leaks by ensuring proper cleanup of unused objects and avoiding unnecessary global variables.