Coding Interview QuestionsInterview Questions and Answers

New 100 JavaScript Interview Question

Table of Contents

Introduction

JavaScript is one of the most popular programming languages used for developing dynamic and interactive web applications. As a student studying programming or preparing for a job interview, it is essential to have a solid understanding of JavaScript concepts and be well-prepared for potential interview questions.

In this guide, we will provide you with a collection of common JavaScript interview questions that students often encounter during technical interviews. These questions are designed to assess your knowledge of JavaScript fundamentals, including syntax, data types, functions, and object-oriented programming concepts.

Throughout this guide, we will cover a variety of topics, such as:

  1. JavaScript Basics: Questions related to the basic syntax, data types, variables, and operators in JavaScript.
  2. Functions: Questions about creating and using functions, understanding function scopes, and passing arguments.
  3. Objects and Prototypes: Questions exploring object-oriented programming concepts, including object creation, inheritance, and prototypes.
  4. DOM Manipulation: Questions about interacting with the Document Object Model (DOM) and manipulating web page elements using JavaScript.
  5. Asynchronous Programming: Questions related to handling asynchronous operations, including callbacks, promises, and async/await.

By studying these interview questions and practicing your answers, you’ll be well-prepared to tackle JavaScript-related questions in your upcoming interviews. Remember to not only memorize the answers but also understand the underlying concepts so that you can apply them effectively in different scenarios.

Basic Questions

1. What is JavaScript?

JavaScript is a popular programming language used for creating dynamic and interactive web pages. It runs on the client-side and allows developers to add functionality, validate forms, manipulate HTML elements, and perform other tasks within a web browser.

2. Differentiate between JavaScript and Java.

JavaScriptJava
Interpreted languageCompiled language
Primarily used for web developmentUsed for various applications, including desktop and mobile development
Dynamically typedStatically typed
Supports prototype-based inheritanceSupports class-based inheritance
Designed to run in a web browserCan be run on any device with a Java Virtual Machine (JVM)

3. What are the different types of data types in JavaScript?

JavaScript has several built-in data types, including:

  • String: Represents textual data.
  • Number: Represents numeric values.
  • Boolean: Represents either true or false.
  • Object: Represents a collection of key-value pairs.
  • Array: Represents an ordered list of values.
  • Null: Represents the intentional absence of any object value.
  • Undefined: Represents an uninitialized variable or missing property.

4. What is the use of NaN in JavaScript?

NaN stands for “Not a Number” and is a special value in JavaScript. It is returned when a mathematical operation fails or when a function attempting to parse a number fails. The use of NaN includes:

  • Indicating the result of an invalid or undefined mathematical operation.
  • Performing type-checking to identify non-numeric values.
  • Detecting errors while parsing numeric inputs.

5. What are undefined and null in JavaScript?

In JavaScript, undefined and null are special values used to represent the absence or unavailability of a meaningful value.

  • undefined: It is the default value assigned to variables that have been declared but not assigned a value. It indicates that the variable doesn’t have a defined value.
JavaScript
let x;
console.log(x);  // Output: undefined
  • null: It is a value assigned to a variable to indicate that it intentionally has no value or absence of an object.
JavaScript
let y = null;
console.log(y);  // Output: null

6. What is the ‘this’ keyword in JavaScript?

The this keyword in JavaScript refers to the object on which a function is being invoked. It provides a way to access properties and methods within an object’s scope.

JavaScript
const person = {
  name: 'John',
  greet: function() {
    console.log(`Hello, ${this.name}!`);
  }
};

person.greet();  // Output: Hello, John!

In the above example, this.name accesses the name property of the person object within the greet function.

7. What is a closure in JavaScript?

A closure is a combination of a function and the lexical environment within which it was declared. It allows a function to access variables from its outer scope, even after the outer function has finished executing.

JavaScript
function outer() {
  const message = 'Hello';

  function inner() {
    console.log(message);
  }

  return inner;
}

const closure = outer();
closure();  // Output: Hello

In the above example, the inner function forms a closure with the variable message defined in the outer scope of outer(). The returned inner function can still access and use the message variable even after the outer function has completed execution.

8. Explain the concept of hoisting in JavaScript.

Hoisting is a JavaScript behavior where variable and function declarations are moved to the top of their containing scope during the compilation phase, regardless of where they are actually declared in the code.

JavaScript
console.log(x);  // Output: undefined
var x = 5;

In the above example, even though the variable x is accessed before its declaration, it doesn’t result in an error. This is because the variable declaration is hoisted to the top, and its initial value is undefined until the assignment is encountered.

9. What is the difference between ‘==’ and ‘===’ operators?

The == and === are comparison operators in JavaScript.

  • == (loose equality): It compares values after performing type coercion, meaning it converts the operands to a common type before comparison.
JavaScript
console.log(5 == '5');   // Output: true
console.log(true == 1);  // Output: true
  • === (strict equality): It compares both the values and types of the operands without performing type coercion.
JavaScript
console.log(5 === '5');   // Output: false
console.log(true === 1);  // Output: false

In the above examples, == performs type coercion while === does not. Therefore, 5 == '5' and true == 1 are evaluated as true, but 5 === '5' and true === 1 are evaluated as false.

10. What are JavaScript Promises?

JavaScript Promises are objects used to handle asynchronous operations. They represent the eventual completion (or failure) of an asynchronous operation and allow us to chain multiple asynchronous operations together.

JavaScript
const fetchData = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('Data fetched successfully!');
    }, 2000);
  });
};

fetchData()
  .then((data) => {
    console.log(data); // Output: Data fetched successfully!
  })
  .catch((error) => {
    console.log(error);
  });

In the above example, the fetchData function returns a Promise that resolves after a 2-second delay. We can use .then() to handle the resolved value and .catch() to handle any errors that occur during the asynchronous operation.

11. What is a callback function in JavaScript?

A callback function in JavaScript is a function that is passed as an argument to another function and is executed inside that function. It allows for asynchronous programming and enables functions to be executed after a specific event or operation.

JavaScript
function fetchData(callback) {
  setTimeout(() => {
    const data = 'Data fetched successfully!';
    callback(data);
  }, 2000);
}

function displayData(data) {
  console.log(data); // Output: Data fetched successfully!
}

fetchData(displayData);

In the above example, the fetchData function takes a callback function as an argument. After a 2-second delay, it invokes the callback function and passes the fetched data to it. The displayData function is passed as a callback and logs the data to the console.

12. Explain how to create an object in JavaScript.

In JavaScript, objects can be created using object literals or constructor functions. Here’s an example of both approaches:

  • Object Literal:
JavaScript
const person = {
  name: 'John',
  age: 25,
  greet: function() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
  }
};

person.greet(); // Output: Hello, my name is John and I am 25 years old.
  • Constructor Function:
JavaScript
function Person(name, age) {
  this.name = name;
  this.age = age;

  this.greet = function() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
  };
}

const person = new Person('John', 25);
person.greet(); // Output: Hello, my name is John and I am 25 years old.

13. What are the different ways to define a JavaScript function?

There are multiple ways to define functions in JavaScript:

  • Function Declaration:
JavaScript
function sayHello() {
  console.log('Hello!');
}
sayHello(); // Output: Hello!
  • Function Expression:
JavaScript
const sayHello = function() {
  console.log('Hello!');
};
sayHello(); // Output: Hello!
  • Arrow Function (ES6):
JavaScript
const sayHello = () => {
  console.log('Hello!');
};
sayHello(); // Output: Hello!

14. What is the purpose of the array methods like map, filter, and reduce?

Array methods like map, filter, and reduce are used to perform common operations on arrays:

  • map: Creates a new array by applying a provided function to each element of the original array.
JavaScript
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((num) => num * 2);
console.log(doubled); // Output: [2, 4, 6, 8, 10]
  • filter: Creates a new array with all elements that pass a provided test.
JavaScript
const numbers = [1, 2, 3, 4, 5];
const evenNumbers = numbers.filter((num) => num % 2 === 0);
console.log(evenNumbers); // Output: [2, 4]
  • reduce: Applies a function to an accumulator and each element in the array, reducing it to a single value.
JavaScript
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
console.log(sum); // Output: 15

15. How can you write a for loop in JavaScript?

A for loop is used to iterate over a block of code a specific number of times. Here’s an example:

JavaScript
for (let i = 0; i < 5; i++) {
  console.log(i); // Output: 0, 1, 2, 3, 4
}

In the above example, the loop initializes a variable i to 0, executes the loop body as long as i is less than 5, increments i by 1 after each iteration.

16. Explain event bubbling and event capturing in JavaScript.

Event bubbling and event capturing are two different phases of event propagation in the DOM (Document Object Model).

  • Event Bubbling: In this phase, when an event is triggered on a nested element, it “bubbles” up through its parent elements, invoking their respective event handlers.
JavaScript
document.getElementById('nested').addEventListener('click', () => {
  console.log('Nested element clicked');
});

document.getElementById('parent').addEventListener('click', () => {
  console.log('Parent element clicked');
});

document.getElementById('grandparent').addEventListener('click', () => {
  console.log('Grandparent element clicked');
});

If you click the nested element, the event will bubble up, and you will see the following output:

JavaScript
Nested element clicked
Parent element clicked
Grandparent element clicked
  • Event Capturing: In this phase, the event is captured from the top-level element and propagates down to the target element.
JavaScript
document.getElementById('grandparent').addEventListener('click', () => {
  console.log('Grandparent element clicked');
}, true);

document.getElementById('parent').addEventListener('click', () => {
  console.log('Parent element clicked');
}, true);

document.getElementById('nested').addEventListener('click', () => {
  console.log('Nested element clicked');
}, true);

With event capturing, if you click the nested element, the event will capture from the top-level element, and you will see the following output:

JavaScript
Grandparent element clicked
Parent element clicked
Nested element clicked

17. What is JSON and how can you fetch data from a JSON file?

JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is used to represent structured data as a collection of key-value pairs.

To fetch data from a JSON file, you can use the fetch() function in JavaScript:

JavaScript
fetch('data.json')
  .then((response) => response.json())
  .then((data) => {
    console.log(data);
  })
  .catch((error) => {
    console.log(error);
  });

In the above example, the fetch() function is used to make an HTTP request to the JSON file. The response.json() method is used to extract the JSON data from the response. The data can then be accessed and used in the second .then() block.

18. How do you handle exceptions in JavaScript?

Exceptions in JavaScript can be handled using try-catch blocks. The try block contains the code that may throw an exception, and the catch block is used to handle the exception if it occurs.

JavaScript
try {
  // Code that may throw an exception
  throw new Error('Something went wrong');
} catch (error) {
  // Code to handle the exception
  console.log(error.message); // Output: Something went wrong
}

In the above example, the throw statement is used to manually throw an exception. The catch block catches the exception and executes the code inside it, logging the error message to the console.

19. What is the difference between localStorage and sessionStorage in the web storage API?

localStoragesessionStorage
Persists data beyond the current sessionPersists data only within the current session
Data is shared across all tabs and windows of the same originData is specific to the tab or window that created it
Data remains stored until explicitly cleared or removedData is cleared when the session ends or the tab/window is closed
Accessed using the localStorage objectAccessed using the sessionStorage object

20. How can you make a redirect page with JavaScript?

To redirect to a different page using JavaScript, you can use the window.location object and set its href property to the desired URL.

JavaScript
// Redirect to a different page
window.location.href = 'https://example.com';

In the above example, window.location.href is set to the URL you want to redirect to. Once the code is executed, the browser will navigate to the specified URL.

21. What are the different scopes of a variable in JavaScript?

In JavaScript, variables have three different scopes:

  • Global Scope: Variables declared outside any function or block have a global scope and can be accessed from anywhere within the program.
  • Function Scope: Variables declared inside a function have a function scope and are only accessible within that function, including any nested functions.
  • Block Scope: Variables declared with let or const inside a block (e.g., within an if statement or a loop) have block scope and are only accessible within that block.

22. Explain ‘use strict’ in JavaScript.

'use strict' is a directive that enables strict mode in JavaScript. It helps catch common mistakes and enforces stricter rules for writing JavaScript code.

JavaScript
'use strict';

// Code written in strict mode

In the above example, placing the 'use strict' directive at the beginning of a script or function enables strict mode for that code block.

23. What are ES6 classes and how are they different from constructors?

ES6 classes are a syntactical sugar over the existing prototype-based inheritance in JavaScript. They provide a more familiar class-based syntax for creating objects and managing inheritance.

JavaScript
class Person {
  constructor(name) {
    this.name = name;
  }

  greet() {
    console.log(`Hello, my name is ${this.name}`);
  }
}

const person = new Person('John');
person.greet(); // Output: Hello, my name is John

In the above example, the Person class is defined using the class keyword. It has a constructor that sets the name property, and a greet method. Objects can be created using the new keyword followed by the class name, just like constructor functions.

24. What are arrow functions in JavaScript? How are they different from traditional functions?

Arrow functions, introduced in ES6, are a concise syntax for writing JavaScript functions. They have a more compact syntax and lexically bind the this value.

JavaScript
// Traditional function
function add(a, b) {
  return a + b;
}

// Arrow function
const add = (a, b) => a + b;

In the above example, the traditional function add and the arrow function add both perform the same addition operation. The arrow function omits the function keyword and uses a fat arrow (=>) between the parameter list and the function body. Arrow functions also have implicit return if the function body is a single expression.

25. What is destructuring assignment in ES6?

Destructuring assignment is a feature in ES6 that allows you to extract values from arrays or properties from objects and assign them to variables in a concise way.

JavaScript
// Array Destructuring
const numbers = [1, 2, 3];
const [a, b, c] = numbers;
console.log(a, b, c); // Output: 1 2 3

// Object Destructuring
const person = { name: 'John', age: 25 };
const { name, age } = person;
console.log(name, age); // Output: John 25

In the above examples, array destructuring is used to assign values from an array to variables, and object destructuring is used to extract property values into variables. It provides a concise way to access and use the values stored in arrays or objects.

27. What are JavaScript generators?

JavaScript generators are special functions that can be paused and resumed, allowing for the generation of a sequence of values over time. They are defined using the

function* syntax and utilize the yield keyword.

JavaScript
function* generateSequence() {
  yield 1;
  yield 2;
  yield 3;
}

const generator = generateSequence();

console.log(generator.next().value); // Output: 1
console.log(generator.next().value); // Output: 2
console.log(generator.next().value); // Output: 3

In the above example, the generateSequence generator function uses the yield keyword to generate a sequence of values. Each call to generator.next().value retrieves the next value from the generator.

28. What are async functions in JavaScript?

Async functions are a syntactical feature in JavaScript that allows writing asynchronous code using a synchronous-looking syntax. They are defined using the async keyword and always return a Promise.

JavaScript
function fetchData() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve('Data fetched successfully!');
    }, 2000);
  });
}

async function getData() {
  const data = await fetchData();
  console.log(data); // Output: Data fetched successfully!
}

getData();

In the above example, the getData function is defined as an async function. Within the function, the await keyword is used to pause the execution until the Promise returned by fetchData() resolves. The value of the resolved Promise is then assigned to the data variable.

29. What are the differences between var, let, and const in JavaScript?

varletconst
Function-scopedBlock-scopedBlock-scoped
Hoisted to the top of their scopeNot hoistedNot hoisted
Can be redeclared and reassignedCannot be redeclared, but can be reassignedCannot be redeclared or reassigned
Can be accessed before they are declared (resulting in undefined)Throws a ReferenceError if accessed before declarationThrows a ReferenceError if accessed before declaration
Commonly used in pre-ES6 JavaScriptPreferred choice for variable declaration in ES6+

30. What are JavaScript modules?

JavaScript modules are reusable pieces of code that encapsulate related functionality. They allow us to separate code into separate files and import/export variables, functions, or classes between different modules.

moduleA.js

JavaScript
export const name = 'John';
export function greet() {
  console.log(`Hello, ${name}!`);
}

moduleB.js

JavaScript
import { name, greet } from './moduleA.js';

console.log(name);  // Output: John
greet();            // Output: Hello, John!

In the above example, moduleA.js exports the name variable and greet function using the export keyword. These exports can then be imported into moduleB.js using the import keyword. The exported variables and functions can be used within the importing module.

31. Explain how DOM manipulation is done in JavaScript.

DOM (Document Object Model) manipulation is the process of interacting with HTML elements using JavaScript. It allows us to dynamically modify the structure, content, and styles of a web page.

Here’s a basic example of DOM manipulation:

JavaScript
// HTML
<!-- <div id="myElement">Hello, World!</div> -->

// JavaScript
const element = document.getElementById('myElement');
element.textContent = 'Hello, JavaScript!';
element.style.color = 'red';

In the above example, the JavaScript code selects the HTML element with the ID myElement using getElementById(). Then, it modifies the text content of the element using the textContent property and changes the color of the text using the style object.

Intermediate Questions

1. What are the different types of Prototypal Inheritance?

There are several types of prototypal inheritance in JavaScript:

  1. Prototype Chain Inheritance: Objects inherit properties and methods directly from their prototype through the [[Prototype]] property. This forms a chain where each object’s prototype is linked to its parent object’s prototype, creating a prototype chain.
  2. Constructor Inheritance: Constructor functions can be used to create objects that inherit properties and methods from a prototype. The new keyword is used to create instances of the constructor function, which inherit from the constructor’s prototype.
  3. Object.create() Inheritance: The Object.create() method creates a new object with the specified prototype object. This allows for direct inheritance, where the newly created object inherits from the specified prototype.
  4. Class Inheritance (ES6): With the introduction of ES6, JavaScript has a class syntax that provides a more familiar way to define and inherit from classes. Classes can be used to create objects that inherit properties and methods from a class using the extends keyword.
  5. Mixin Inheritance: Mixins are objects or functions that can be used to add specific behavior to an object by merging or copying properties and methods. By combining multiple mixins, objects can inherit from multiple sources.

2. Explain the concept of Temporal Dead Zone in ES6.

In ES6, the Temporal Dead Zone (TDZ) is a behavior that occurs during the variable declaration phase. It is a period between the start of a block scope and the point at which a variable is declared, where accessing the variable results in a ReferenceError.

The TDZ concept is related to the use of block-scoped variables declared with let and const. Unlike variables declared with var, which are hoisted to the top of their scope, variables declared with let and const remain inaccessible until they are declared.

During the TDZ, if you try to access a block-scoped variable before its declaration, JavaScript throws a ReferenceError. This behavior prevents accessing variables before they are properly initialized and promotes better code quality.

Here’s an example to illustrate the Temporal Dead Zone:

JavaScript
console.log(x); // Output: ReferenceError: x is not defined

let x = 10;
console.log(x); // Output: 10

In this example, accessing the variable x before its declaration results in a ReferenceError due to the TDZ. Only after the variable is declared with let x = 10 can it be accessed without an error.

3. What are Symbols in ES6?

In ES6, Symbols are a new primitive data type introduced to JavaScript. They are unique, immutable values that can be used as property keys for object properties. Symbols are created using the Symbol() function.

The main characteristics of Symbols are:

  • Uniqueness: Each Symbol value is unique and cannot be duplicated. Even if two Symbols have the same description, they are different values.
  • Immutable: Symbols are immutable and cannot be changed or modified.
  • Privacy: Symbols can be used as property keys to define non-enumerable properties on objects. This makes Symbols useful for creating private or internal properties that are not meant to be accessed or modified by external code.

4. What are Higher Order Functions in JavaScript?

Higher-order functions in JavaScript are functions that can accept other functions as arguments and/or return functions as their results. They treat functions as first-class citizens, allowing them to be manipulated and used as data.

Here’s an example of a higher-order function that takes a function as an argument:

JavaScript
function greet(name, callback) {
  const message = `Hello, ${name}!`;
  callback(message);
}

function displayMessage(message) {
  console.log(message);
}

greet("John", displayMessage); // Output: Hello, John!

In the above example, the greet function is a higher-order function that takes two arguments: name and callback. The callback argument is a function that will be invoked within greet. In this case, the displayMessage function is passed as the callback argument, and it logs the message to the console.

Higher-order functions enable more flexible and modular code by allowing functions to be composed and reused in various contexts. They are often used in functional programming paradigms and can be found in many JavaScript built-in methods like map, filter, and reduce.

5. Explain Event Delegation in JavaScript.

Event delegation is a technique in JavaScript where instead of attaching an event listener to each individual element, a single event listener is added to a parent element. This listener then handles events that occur on its descendant elements.

The main advantages of event delegation are:

  • Improved Performance: By attaching a single event listener to a parent element, you reduce the number of event listeners in the DOM. This can significantly improve performance, especially when dealing with a large number of elements or dynamically added elements.
  • Dynamic Event Handling: Event delegation allows for handling events on elements that are added or removed dynamically from the DOM. Since the parent element remains constant, new elements automatically inherit the event handling without needing to add or remove event listeners explicitly.
  • Simplified Code: Event delegation simplifies the code by reducing the need to attach event listeners to multiple elements. It promotes a more concise and efficient code structure.

Here’s an example to illustrate event delegation:

HTML
<ul id="myList">
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
</ul>
JavaScript
const myList = document.getElementById('myList');

myList.addEventListener('click', function(event) {
  if (event.target.nodeName === 'LI') {
    console.log('Clicked on:', event.target.textContent);
  }
});

In this example, instead of attaching a click event listener to each <li> element, a single event listener is added to the parent <ul> element. When a click event occurs, the event bubbles up from the clicked <li> to the <ul> element, and the event listener is triggered. By checking the event.target property, the specific <li> element that was clicked can be identified and appropriate actions can be taken.

6. What is currying in JavaScript and when might you use this technique?

Currying is a technique in JavaScript where a function with multiple arguments is transformed into a sequence of functions, each taking a single argument. The curried function returns a new function for each argument until all arguments are provided, and then the final result is returned.

Here’s an example to illustrate currying:

JavaScript
function multiply(a) {
  return function(b) {
    return a * b;
  };
}

const multiplyByTwo = multiply(2);
console.log(multiplyByTwo(4)); // Output: 8

In the above example, the multiply function takes the first argument a and returns an inner function that takes the second argument b. The inner function, when invoked, multiplies a with b and returns the result.

Currying is often useful in scenarios where you have a function that can be partially applied with certain arguments upfront, and you want to reuse that partially applied function with different arguments later. It allows for creating specialized versions of a function that can be used in different contexts without repeating the same arguments.

Some benefits and use cases of currying include:

  1. Partial application: Currying allows you to create partially applied functions by fixing some arguments, which can be useful in scenarios where you want to reuse a function with certain arguments while leaving others open for later.
  2. Reusability: Curried functions can be reused and composed to build more complex functions.
  3. Modularity: Currying promotes code modularity by breaking down complex functions into smaller, reusable units.

7. What are JavaScript Mixins?

JavaScript mixins are a way to extend the functionality of an object by combining the properties and methods from multiple sources. It is a technique that allows code reuse and composition without the need for traditional class inheritance.

Mixins are typically implemented using object composition or function composition. They can be used to add new behavior to an object or enhance existing behavior by merging in the properties and methods from other objects or functions.

Here’s an example to illustrate the concept of mixins:

JavaScript
// Mixin object
const sayHelloMixin = {
  sayHello() {
    console.log("Hello!");
  }
};

// Target object
const person = {};

// Applying the mixin
Object.assign(person, sayHelloMixin);

person.sayHello(); // Output: Hello!

In the above example, the sayHelloMixin object defines a sayHello method. We then use Object.assign to merge the properties and methods from the sayHelloMixin object into the person object, effectively adding the sayHello method to the person object.

8. Explain the difference between ‘null’ and ‘undefined’.

nullundefined
Represents an intentional absence of any object valueRepresents an unintentional absence of a defined value
It is an assignment value that can be explicitly assigned to a variableIt is a primitive value automatically assigned to variables that have been declared but not assigned a value
When explicitly assigned, it indicates that a variable has no value or an empty valueIndicates a variable or property has been declared but has not been assigned any value yet
typeof null returns “object”typeof undefined returns “undefined”
Example: let name = null;Example: let age;

9. How does ‘Function.prototype.bind’ work in JavaScript?

The bind() method in JavaScript is used to create a new function that, when invoked, has a bound this value and potentially pre-set arguments. It allows you to control the execution context of a function and provides a way to create function references with specific this values.

When bind() is called on a function, it returns a new function with the same body and scope as the original function, but with a permanently bound this value.

Here’s an example to illustrate the usage of bind():

JavaScript
const person = {
  name: 'John',
  greet: function() {
    console.log('Hello, ' + this.name + '!');
  }
};

const boundGreet = person.greet.bind(person);
boundGreet(); // Output: Hello, John!

In this example, the bind() method is used to create a new function boundGreet that is permanently bound to the person object. When boundGreet() is invoked, the this value within the function is set to person, regardless of how the function is called.

10. What are JavaScript decorators?

JavaScript decorators are a language feature introduced in ECMAScript (ES) standards, specifically ES2016 and later versions. Decorators are a way to modify the behavior of classes, methods, or properties by wrapping them with higher-order functions called decorators.

Decorators are defined using the @ symbol followed by a function or expression. They are placed immediately before the class, method, or property they intend to modify. When the code is executed, the decorator is invoked and can alter the target object or add additional functionality.

Here’s an example to illustrate the usage of decorators:

JavaScript
function log(target, name, descriptor) {
  const originalMethod = descriptor.value;
  descriptor.value = function (...args) {
    console.log(`Calling ${name} with arguments: ${args}`);
    const result = originalMethod.apply(this, args);
    console.log(`Method ${name} returned: ${result}`);
    return result;
  };
  return descriptor;
}

class Calculator {
  @log
  add(a, b) {
    return a + b;
  }
}

const calc = new Calculator();
console.log(calc.add(2, 3)); // Output: Calling add with arguments: 2, 3 // Method add returned: 5 // 5

In the above example, the log decorator is defined as a higher-order function. It receives the target object, the method name, and a descriptor object. It wraps the original method by modifying the descriptor object’s value property. In this case, the decorator adds logging statements before and after the method is invoked.

Decorators can be used for various purposes, such as:

  • Logging and debugging
  • Adding validation or error checking
  • Applying access control or permissions
  • Modifying the behavior of methods or properties
  • Implementing aspects like caching or memoization

It’s important to note that decorators are a proposal in JavaScript and may require a transpiler like Babel to use them in current environments.

11. Explain try-catch-finally statement in JavaScript.

The try-catch-finally statement in JavaScript is used to handle exceptions and control the flow of execution in error-prone code blocks. It allows you to attempt a block of code that may throw an exception and provides a way to handle and recover from any thrown exceptions.

The basic syntax of try-catch-finally is as follows:

JavaScript
try {
  // Code that might throw an exception
} catch (error) {
  // Code to handle the exception
} finally {
  // Code that always executes, regardless of whether an exception was thrown
}

Here’s how the try-catch-finally statement works:

  1. The code within the try block is executed. If an exception is thrown during the execution of this block, the normal flow of execution is immediately transferred to the corresponding catch block.
  2. If an exception is thrown, the catch block is executed. The catch block takes an error parameter that represents the thrown exception. You can use this block to handle or process the exception, log error messages, or take any necessary recovery actions.
  3. The finally block is optional. It contains code that is executed regardless of whether an exception was thrown or caught. This block is commonly used to perform cleanup operations, such as closing resources or releasing memory, that need to be executed regardless of the exception handling.

The try-catch-finally statement allows you to handle exceptions and gracefully recover from errors, preventing your program from terminating unexpectedly. It provides a structured way to handle exceptional cases and ensures that critical cleanup operations are performed, even in the presence of exceptions.

12. Explain the differences between ‘throw’ and ‘throw new Error’.

In JavaScript, both throw and throw new Error are used to throw exceptions, but they have slight differences:

  • throw: The throw statement is used to throw any value as an exception. It can be used with any type of value, such as strings, numbers, objects, or custom error types. However, when using throw without specifying an error type, the error message may not be as descriptive or standardized.
  • throw new Error: The throw new Error statement is specifically used to throw instances of the Error object or its subclasses. It creates a new instance of the Error object and throws it as an exception. This approach provides more standardized error handling and allows for more detailed error messages, stack traces, and additional error properties.

Here’s an example to illustrate the difference:

JavaScript
throw 'Something went wrong'; // Throws a string as an exception
throw new Error('Something went wrong'); // Throws an Error object with a descriptive error message

Using throw new Error allows you to create more meaningful and standardized error objects with additional properties and stack traces. It is generally recommended to use throw new Error or custom error types for better error handling and debugging capabilities.

13. How can you clone an object in JavaScript?

In JavaScript, there are several ways to clone an object, each with its own characteristics and considerations. Here are a few common approaches:

  1. Using the spread operator:
JavaScript
const originalObject = { key: 'value' };
const clonedObject = { ...originalObject };
  1. Using Object.assign():
JavaScript
const originalObject = { key: 'value' };
const clonedObject = Object.assign({}, originalObject);
  1. Using JSON.parse() and JSON.stringify() (works for objects without functions or non-serializable values):
JavaScript
const originalObject = { key: 'value' };
const clonedObject = JSON.parse(JSON.stringify(originalObject));
  1. Using the lodash.cloneDeep() method from the Lodash library (for deep cloning):
JavaScript
const originalObject = { key: 'value' };
const clonedObject = _.cloneDeep(originalObject);

It’s important to note that the above approaches create a shallow clone, meaning that the properties are copied by value, but if the object contains nested objects, only references to them will be copied. If you need a deep clone (creating copies of nested objects as well), you can use the JSON method or a dedicated library like Lodash’s cloneDeep().

14. What is a JavaScript Generator and how is it different from a regular function?

A JavaScript Generator is a special type of function that can be paused and resumed during its execution. It allows you to control the flow of execution and generate a sequence of values over time.

Here are the key characteristics of Generators:

  • Pausing and Resuming: Generators can be paused using the yield keyword, which allows them to return a value temporarily and then resume execution from where they left off. This is different from regular functions, which execute from start to finish in one go.
  • Iterability: Generators are iterables, meaning they can be used in for...of loops and other constructs that expect iterables. Each yield statement produces a value that can be consumed one at a time.
  • State Maintenance: Generators maintain their internal state across multiple invocations, allowing them to remember the execution context and resume where they left off.
  • Asynchronous Programming: Generators are often used in asynchronous programming to simplify control flow and make async code look more like synchronous code.

Here’s an example to demonstrate a Generator:

JavaScript
function* numberGenerator() {
  yield 1;
  yield 2;
  yield 3;
}

const generator = numberGenerator();
console.log(generator.next().value); // Output: 1
console.log(generator.next().value); // Output: 2
console.log(generator.next().value); // Output: 3

In this example, the numberGenerator() function is a Generator that yields a sequence of numbers. Each call to generator.next() returns an object with a value property representing the yielded value. By repeatedly calling generator.next(), we can consume the values generated by the Generator.

15. What is the importance of ‘JavaScript Module Pattern’ and when do you use it?

The JavaScript Module Pattern is a design pattern that allows for encapsulation, private data, and the creation of self-contained modules. It provides a way to organize code, prevent naming conflicts, and expose only specific functionality to the outside world.

The key features and benefits of the Module Pattern are:

  • Encapsulation: The Module Pattern encapsulates related data and functions into a single module, preventing them from polluting the global scope and avoiding naming collisions with other modules or scripts.
  • Privacy and Data Protection: The Module Pattern allows for the creation of private data and methods within a module that are inaccessible from the outside. This helps maintain data integrity and provides better control over module internals.
  • Reusability: Modules created using the Module Pattern are highly reusable and can be easily included in different parts of an application without causing conflicts or dependencies.
  • Namespacing: Modules provide a way to create namespaces, preventing function and variable clashes between different parts of an application. This improves code organization and helps developers better understand the dependencies and relationships between modules.

16. What is an IIFE ( Immediately Invoked Function Expression) and why might you use it?

An Immediately Invoked Function Expression (IIFE) is a JavaScript function that is declared and executed immediately after it is defined. It is a self-invoking function that does not need to be called explicitly.

The primary reasons to use an IIFE are:

  • Encapsulation: IIFEs provide a way to create a private scope for variables and functions within the function, preventing them from polluting the global scope. This helps avoid naming conflicts and provides data privacy.
  • Isolation: By executing the function immediately, you can isolate variables and functions within the IIFE, ensuring they do not interfere with other parts of the code.
  • Initialization: IIFEs can be used to initialize values, set up configurations, or perform any one-time actions during script execution.

Here’s an example of an IIFE:

JavaScript
(function() {
  // IIFE code
  var message = 'Hello, IIFE!';
  console.log(message);
})();

In this example, the function is defined using an anonymous function expression (function() { ... }), and the parentheses (function() { ... })() immediately invoke the function. The code inside the IIFE is executed immediately, creating a private scope and printing the message to the console.

17. What is currying in JavaScript and when might you use this technique?

Currying is a technique in functional programming where a function that takes multiple arguments is transformed into a sequence of functions, each taking a single argument. This allows for partial application of arguments, creating new functions that are specialized versions of the original function.

Here’s an example to illustrate currying in JavaScript:

Java
function multiply(a) {
  return function(b) {
    return a * b;
  };
}

const multiplyByTwo = multiply(2);
console.log(multiplyByTwo(4)); // Output: 8

In the above example, the multiply function takes the first argument a and returns a new function that takes the second argument b. When multiplyByTwo is invoked with 4, it multiplies 4 by the original 2 and returns the result 8.

Currying provides flexibility and reusability in function composition. It allows you to create specialized versions of functions by fixing some arguments upfront and leaving others open for later. This can be useful in scenarios where you have a function with common parameters that you want to reuse across different contexts with varying specific arguments.

Benefits and use cases of currying include:

  1. Partial application: Currying enables you to create partially applied functions by fixing certain arguments, allowing for code reuse and specialization.
  2. Reusability: Curried functions can be reused and composed to build more complex functions.
  3. Modularity: Currying promotes code modularity by breaking down complex functions into smaller, reusable units.

18. What are JavaScript Mixins?

JavaScript mixins are a way to extend the functionality of an object by combining the properties and methods from multiple sources. They allow code reuse and composition without the need for traditional class inheritance.

Mixins can be implemented using object composition or function composition. They provide a mechanism to add new behavior to an object or enhance existing behavior by merging in the properties and methods from other objects or functions.

Here’s an example to illustrate the concept of mixins using object composition:

Java
// Mixin objects
const canEat = {
  eat() {
    console.log("Eating...");
  }
};

const canSleep = {
  sleep() {
    console.log("Sleeping...");
  }
};

// Target object
const cat = {};

// Applying mixins
Object.assign(cat, canEat, canSleep);

// Using the mixed-in methods
cat.eat(); // Output: Eating...
cat.sleep(); // Output: Sleeping...

In the above example, we define two mixin objects: canEat and canSleep, each containing specific methods. Then, we create a target object called cat. By using Object.assign, we merge the properties and methods from the mixin objects into the cat object, effectively adding the behaviors of eating and sleeping.

19. Explain the difference between ‘null’ and ‘undefined’.

In JavaScript, null and undefined are both values that indicate the absence of a value, but they have different meanings:

  • null: It is a value that represents the intentional absence of any object value. It is typically assigned to a variable to indicate that it has no value or that an object property does not exist.
  • undefined: It is a value that indicates the absence of an assigned value. It is the default value of variables that have been declared but have not been assigned a value, function parameters that have not been provided, or object properties that have not been defined.

20. How does ‘Function.prototype.bind’ work in JavaScript?

The bind() method in JavaScript is used to create a new function that, when invoked, has a bound this value and potentially pre-set arguments. It allows you to control the execution context of a function and provides a way to create function references with specific this values.

When bind() is called on a function, it returns a new function with the same body and scope as the original function, but with a permanently bound this value.

Here’s an example to illustrate the usage of bind():

JavaScript
const person = {
  name: 'John',
  greet: function() {
    console.log('Hello, ' + this.name + '!');
  }
};

const boundGreet = person.greet.bind(person);
boundGreet(); // Output: Hello, John!

In this example, the bind() method is used to create a new function boundGreet that is permanently bound to the person object. When boundGreet() is invoked, the this value within the function is set to person, regardless of how the function is called.

21. What are JavaScript decorators?

JavaScript decorators are a language feature introduced in ECMAScript (ES) standards, specifically ES2015 and later versions. Decorators provide a way to modify the behavior of classes, methods, or properties by wrapping them with higher-order functions called decorators.

Decorators are defined using the @ symbol followed by a function or expression. They are placed immediately before the class, method, or property they intend to modify. When the code is executed, the decorator is invoked and can alter the target object or add additional functionality.

Here’s an example to demonstrate the usage of decorators:

Java
function log(target, name, descriptor) {
  const originalMethod = descriptor.value;
  descriptor.value = function(...args) {
    console.log(`Calling ${name} with arguments: ${args}`);
    const result = originalMethod.apply(this, args);
    console.log(`Method ${name} returned: ${result}`);
    return result;
  };
  return descriptor;
}

class Calculator {
  @log
  add(a, b) {
    return a + b;
  }
}

const calc = new Calculator();
console.log(calc.add(2, 3)); // Output: Calling add with arguments: 2, 3 // Method add returned: 5 // 5

In the above example, the log decorator is defined as a higher-order function. It receives the target object, the method name, and a descriptor object. It wraps the original method by modifying the descriptor object’s value property. In this case, the decorator adds logging statements before and after the method is invoked.

Decorators can be used for various purposes, such as:

  • Logging and debugging
  • Adding validation or error checking
  • Applying access control or permissions
  • Modifying the behavior of methods or properties
  • Implementing aspects like caching or memoization

22. Explain how ‘try-catch-finally’ works in JavaScript.

The try-catch-finally statement in JavaScript is used to handle exceptions and control the flow of execution in error-prone code blocks. It allows you to attempt a block of code that may throw an exception and provides a way to handle and recover from any thrown exceptions.

The basic syntax of try-catch-finally is as follows:

JavaScript
try {
  // Code that might throw an exception
} catch (error) {
  // Code to handle the exception
} finally {
  // Code that always executes, regardless of whether an exception was thrown
}

Here’s how the try-catch-finally statement works:

  1. The code within the try block is executed. If an exception is thrown during the execution of this block, the normal flow of execution is immediately transferred to the corresponding catch block.
  2. If an exception is thrown, the catch block is executed. The catch block takes an error parameter that represents the thrown exception. You can use this block to handle or process the exception, log error messages, or take any necessary recovery actions.
  3. The finally block is optional. It contains code that is executed regardless of whether an exception was thrown or caught. This block is commonly used to perform cleanup operations, such as closing resources or releasing memory, that need to be executed regardless of the exception handling.

23. Explain the differences between ‘throw’ and ‘throw new Error’.

In JavaScript, both throw and throw new Error are used to throw exceptions, but they have slight differences:

  • throw: The throw statement is used to throw any value as an exception. It can be used with any type of value, such as strings, numbers, objects, or custom error types. However, when using throw without specifying an error type, the error message may not be as descriptive or standardized.
  • throw new Error: The throw new Error statement is specifically used to throw instances of the Error object or its subclasses. It creates a new instance of the Error object and throws it as an exception. This approach provides more standardized error handling and allows for more detailed error messages, stack traces, and additional error properties.

Here’s an example to illustrate the difference:

JavaScript
throw 'Something went wrong'; // Throws a string as an exception

throw new Error('Something went wrong'); // Throws an Error object with a descriptive error message

Using throw new Error allows you to create more meaningful and standardized error objects with additional properties and stack traces. It is generally recommended to use throw new Error or custom error types for better error handling and debugging capabilities.

24. How can you clone an object in JavaScript?

There are several ways to clone an object in JavaScript, depending on the requirements of the cloning process:

  1. Shallow Cloning: To create a shallow clone of an object, you can use techniques like the spread operator ({...obj}), Object.assign(), or the Array.from() method.
  2. Deep Cloning: To create a deep clone that also includes nested objects, you can use techniques like JSON.parse(JSON.stringify(obj)), third-party libraries like Lodash’s _.cloneDeep(), or implement a custom recursive cloning function.

25. What is the importance of ‘JavaScript Module Pattern’ and when do you use it?

The JavaScript Module Pattern is a design pattern that allows for encapsulation, private data, and the creation of self-contained modules. It provides a way to organize code, prevent naming conflicts, and expose only specific functionality to the outside world.

The key features and benefits of the Module Pattern are:

  • Encapsulation: The Module Pattern encapsulates related data and functions into a single module, preventing them from polluting the global scope and avoiding naming collisions with other modules or scripts.
  • Privacy and Data Protection: The Module Pattern allows for the creation of private data and methods within a module that are inaccessible from the outside. This helps maintain data integrity and provides better control over module internals.
  • Reusability: Modules created using the Module Pattern are highly reusable and can be easily included in different parts of an application without causing conflicts or dependencies.
  • Namespacing: Modules provide a way to create namespaces, preventing function and variable clashes between different parts of an application. This improves code organization and helps developers better understand the dependencies and relationships between modules.

26. What is an IIFE ( Immediately Invoked Function Expression) and why might you use it?

An Immediately Invoked Function Expression (IIFE) is a JavaScript function that is declared and executed immediately after it is defined. It is a self-invoking function that does not need to be called explicitly.

The primary reasons to use an IIFE are:

  • Encapsulation: IIFEs provide a way to create a private scope for variables and functions within the function, preventing them from polluting the global scope. This helps avoid naming conflicts and provides data privacy.
  • Isolation: By executing the function immediately, you can isolate variables and functions within the IIFE, ensuring they do not interfere with other parts of the code.
  • Initialization: IIFEs can be used to initialize values, set up configurations, or perform any one-time actions during script execution.

Here’s an example of an IIFE:

JavaScript
(function() {
  // IIFE code
  var message = 'Hello, IIFE!';
  console.log(message);
})();

In this example, the function is defined using an anonymous function expression (function() { ... }), and the parentheses (function() { ... })() immediately invoke the function. The code inside the IIFE is executed immediately, creating a private scope and printing the message to the console.

27. How do you use ‘apply’, ‘call’, and ‘bind’ methods in JavaScript?

The ‘apply’, ‘call’, and ‘bind’ methods are used to invoke functions with a specific context (the value of this) and can pass arguments to the function. Here’s how they work:

  • apply: The apply method allows you to call a function with a specified this value and an array (or an array-like object) of arguments.
JavaScript
function greet(name) {
  console.log(`Hello, ${name}!`);
}

greet.apply(null, ['John']); // Output: Hello, John!
  • call: The call method is similar to apply, but instead of passing an array of arguments, you pass them individually as arguments to the function.
function greet(name) {
  console.log(`Hello, ${name}!`);
}

greet.call(null, 'John'); // Output: Hello, John!
  • bind: The bind method returns a new function with a bound context (this value) and any specified arguments. It allows you to create a function that, when called, will have a specific this value and potentially predefined arguments.
JavaScript
function greet(name) {
  console.log(`Hello, ${name}!`);
}

const greetJohn = greet.bind(null, 'John');
greetJohn(); // Output: Hello, John!

In these examples, null is passed as the first argument because the context (this value) is not relevant in this case.

28. Explain the concept of ‘memoization’ in JavaScript.

‘Memoization’ is a technique in JavaScript used to optimize function performance by caching the results of function calls and reusing them for subsequent identical inputs. It is a form of caching that avoids unnecessary computation by storing function results for specific input arguments.

Here’s a simplified example of memoization:

JavaScript
function memoizedFunction() {
  const cache = {};

  return function(n) {
    if (n in cache) {
      return cache[n];
    } else {
      const result = /* Perform the computation */;
      cache[n] = result;
      return result;
    }
  };
}

const memoizedFn = memoizedFunction();

console.log(memoizedFn(5)); // Output: Cached result or computed value for input 5
console.log(memoizedFn(5)); // Output: Cached result from the previous call

In this example, the memoizedFunction returns a new function that performs a computation and caches the result in the cache object. If the same input argument is encountered again, the cached result is returned instead of recomputing it. This improves the performance of the function by avoiding redundant computations.

29. What are the different ways to handle asynchronous operations in JavaScript?

There are several ways to handle asynchronous operations in JavaScript:

  • Callbacks: Callbacks are a traditional approach where a function accepts a callback function as an argument, which is executed when the asynchronous operation is complete or an error occurs. Callbacks can lead to callback hell and make code harder to read and maintain.
  • Promises: Promises were introduced in ES6 and provide a cleaner and more structured way to handle asynchronous operations. Promises represent a single future value or error that will be available at some point. They allow chaining of operations using .then() and handling errors using .catch().
  • Async/await: Async/await is a syntax introduced in ES8 (ES2017) that simplifies the handling of asynchronous operations even further. It allows writing asynchronous code in a more synchronous and sequential manner, making it easier to understand and maintain. The async keyword is used to define an asynchronous function, and the await keyword is used to wait for a promise to resolve before proceeding.
  • Generators: Generators can be used in combination with Promises to achieve more readable asynchronous code. By using the yield keyword inside a generator function, asynchronous operations can be paused and resumed, allowing for a more sequential flow of code.

30. What are JavaScript Promises and how do they work?

JavaScript Promises are objects used for asynchronous programming. They represent a single future value or error that will be available at some point. Promises simplify handling of asynchronous operations and provide a structured way to chain operations and handle errors.

Promises have three states:

  • Pending: The initial state. The promise is still being resolved or rejected.
  • Fulfilled: The asynchronous operation completed successfully, and the promise is resolved with a value.
  • Rejected: An error occurred during the asynchronous operation, and the promise is rejected with a reason (an error object or a value representing the error).

Here’s an example of a Promise that simulates an asynchronous delay and resolves with a value after a specified time:

JavaScript
function delay(ms) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('Done!');
    }, ms);
  });
}

delay(2000)
  .then((result) => {
    console.log(result); // Output: Done!
  })
  .catch((error) => {
    console.error(error);
  });

In this example, the delay function returns a new Promise. After the specified delay (in milliseconds), the Promise resolves with the value 'Done!'. The then() method is used to handle the fulfilled state, and the catch() method is used to handle any errors that may occur during the asynchronous operation.

Promises can be chained together using the then() method, allowing for a sequential flow of asynchronous operations. They provide a more structured and readable way to handle asynchronous code compared to traditional callbacks.

31. What is a ‘Set’ in JavaScript and provide an example?

A ‘Set’ in JavaScript is a built-in object that allows storing unique values of any type, whether they are primitive values or object references. A Set can only contain unique values, eliminating duplicates automatically.

Here’s an example of using a Set to store unique values:

JavaScript
const set = new Set();

set.add(1);
set.add('Hello');
set.add(true);

console.log(set.has(1)); // Output: true
console.log(set.size); // Output: 3

set.add(1); // Adding a duplicate value, which will be ignored

console.log(set.size); // Output: 3

set.delete('Hello');
console.log(set.size); // Output: 2

set.clear();
console.log(set.size); // Output: 0

In this example, we create a new Set using the new Set() syntax. We can then add values to the Set using the add() method, check if a value exists using the has() method, get the size of the Set using the size property, delete values using the delete() method, and clear all values using the clear() method.

32. What is a ‘Map’ in JavaScript and provide an example?

A ‘Map’ in JavaScript is a built-in object that allows storing key-value pairs, where both the keys and values can be of any type. Unlike objects, Maps preserve the order of elements and allow any value to be used as a key.

Here’s an example of using a Map to store key-value pairs:

JavaScript
const map = new Map();

const key1 = 'key1';
const key2 = {};

map.set(key1, 'Value 1');
map.set(key2, 'Value 2');

console.log(map.get(key1)); // Output: Value 1
console.log(map.get(key2)); // Output: Value 2

console.log(map.size); // Output: 2

map.delete(key1);
console.log(map.size); // Output: 1

console.log(map.has(key2)); // Output: true

map.clear();
console.log(map.size); // Output: 0

In this example, we create a new Map using the new Map() syntax. We can then add key-value pairs using the set() method, retrieve values using the get() method, check if a key exists using the has() method, get the size of the Map using the size property, delete key-value pairs using the delete() method, and clear all key-value pairs using the clear() method.

33. What is the significance of ‘async/await’ in JavaScript and how does it work?

async/await‘ is a syntax introduced in ES8 (ES2017) for handling asynchronous operations in a more synchronous and readable manner. It provides a way to write asynchronous code that looks and behaves more like synchronous code, making it easier to understand and maintain.

The ‘async‘ keyword is used to define an asynchronous function, which returns a Promise. Inside an ‘async‘ function, the ‘await‘ keyword is used to pause the execution of the function until a Promise is resolved or rejected. This allows sequential execution of asynchronous operations, similar to how synchronous code flows.

Here’s an example that demonstrates the usage of ‘async/await’:

JavaScript
function delay(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

async function asyncFunction() {
  console.log('Before delay');
  await delay(2000);
  console.log('After delay');
}

asyncFunction();

In this example, the asyncFunction is defined as an asynchronous function using the ‘async’ keyword. Inside the function, the await keyword is used to pause the execution at the await delay(2000) line until the delay Promise resolves. This ensures that the ‘After delay’ message is logged after a delay of 2000 milliseconds.

By using ‘async/await‘, you can write asynchronous code in a more readable and sequential manner, without relying on callbacks or chaining promises using .then(). It simplifies error handling as well, allowing the use of try-catch blocks to handle potential errors within the asynchronous code block.

Advanced Questions

1. How does JavaScript handle automatic type conversion?

JavaScript uses automatic type conversion, also known as type coercion, to convert values from one type to another when performing operations or comparisons. It tries to make the operation valid by converting one or both operands to a compatible type.

Here’s an example:

JavaScript
// Numeric addition
var num = 10;
var str = "5";

var result = num + str;
console.log(result); // "105" (string concatenation)

// Comparison
var num1 = 10;
var num2 = "5";

var isEqual = num1 == num2;
console.log(isEqual); // true (number 5 is converted to a string and compared)

In the first example, the + operator is used with a number and a string. JavaScript converts the number 10 to a string and performs string concatenation instead of numeric addition.

In the second example, the == operator is used to compare a number and a string. JavaScript converts the string "5" to a number and performs the comparison, considering them equal.

2. What is ‘hoisting’? How does it work?

Hoisting is a JavaScript behavior where variable and function declarations are moved to the top of their containing scope during the compilation phase. This means that you can use variables and functions before they are declared in the code.

Here’s an example:

JavaScript
console.log(num); // undefined
var num = 5;

hoistedFunction(); // "This is a hoisted function."

function hoistedFunction() {
  console.log("This is a hoisted function.");
}

In this example, the variable num and the function hoistedFunction are referenced before their declarations. However, due to hoisting, the code is interpreted as if the declarations were moved to the top of their scope.

The console.log(num) statement outputs undefined because the variable is declared but not yet assigned a value. The function hoistedFunction can be called before its actual declaration, and it prints the expected message.

3. What is a closure? Can you provide an example of a closure in JavaScript?

A closure is a combination of a function and the lexical environment within which it was declared. It allows a function to access variables from an outer function, even after the outer function has finished executing.

Here’s an example:

JavaScript
function outerFunction() {
  var outerVariable = "I'm from the outer function.";

  function innerFunction() {
    console.log(outerVariable);
  }

  return innerFunction;
}

var closure = outerFunction();
closure(); // "I'm from the outer function."

In this example, the outerFunction defines a variable outerVariable and an inner function innerFunction. The innerFunction has access to the outerVariable due to closure. When outerFunction is called and returns the innerFunction, the variable outerVariable is still accessible and can be accessed by invoking closure().

4. What is the event loop in JavaScript? How does it work?

The event loop is a mechanism in JavaScript that handles asynchronous operations and ensures that the execution of code continues smoothly. It enables JavaScript to be single-threaded while handling concurrent tasks asynchronously.

Here’s an example:

JavaScript
console.log("Start");

setTimeout(function () {
  console.log("Inside setTimeout");
}, 0);

Promise.resolve().then(function () {
  console.log("Inside Promise");
});

console.log("End");

In this example, the code first logs "Start" and "End" synchronously. Then, it schedules two asynchronous operations: a setTimeout callback and a Promise callback.

The event loop continuously checks if there are any pending tasks in the event queue. In this case, the setTimeout callback and the Promise callback are added to the event queue after their specified delay or when the promise is resolved.

After the synchronous code finishes executing, the event loop processes the pending tasks in the event queue. The setTimeout callback and the Promise callback are executed, resulting in the output:

JavaScript
Start
End
Inside Promise
Inside setTimeout

5. What are the pros and cons of using Promises instead of callbacks?

Promises provide a more structured and elegant way to handle asynchronous operations compared to traditional callbacks. Here are some pros and cons:

Pros of Promises:

  • Promotes better code organization with a clear separation of concerns.
  • Allows chaining multiple asynchronous operations using then method.
  • Provides better error handling with the catch method.
  • Enables easier conversion of callback-based code to Promise-based code.

Cons of Promises:

  • Requires familiarity with the Promise API.
  • Can lead to excessive nesting of then callbacks when multiple asynchronous operations are involved.
  • Not supported in older versions of JavaScript (prior to ES6), requiring polyfills or transpilers.

Here’s an example comparing a callback-based approach to a Promise-based approach:

Callback-based approach:

JavaScript
function asyncOperation(callback) {
  setTimeout(function () {
    callback(null, "Data");
  }, 1000);
}

asyncOperation(function (err, data) {
  if (err) {
    console.error("Error:", err);
  } else {
    console.log("Data:", data);
  }
});

Promise-based approach:

JavaScript
function asyncOperation() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve("Data");
    }, 1000);
  });
}

asyncOperation()
  .then(function (data) {
    console.log("Data:", data);
  })
  .catch(function (err) {
    console.error("Error:", err);
  });

In the callback-based approach, the asynchronous operation is passed a callback function to handle the result or error. In the Promise-based approach, the asyncOperation function returns a Promise that can be chained with then and catch methods, making the code more readable and maintainable.

6. What is the difference between a ‘shallow copy’ and a ‘deep copy’ of an object?

Shallow CopyDeep Copy
1.Copies the references of nested objectsCreates a completely independent copy
2.Modifying nested objects affects the original objectModifying nested objects doesn’t affect the original object
3.Copying is performed on the top-level onlyCopying is performed recursively for all levels
4.Objects share the same memoryObjects have separate memory
5.Less memory consumptionMore memory consumption
6.Faster to performSlower to perform

7. Explain the concept of prototypical inheritance. How is it different from classical inheritance?

Prototypical inheritance is a way of creating objects where an object inherits properties and methods directly from another object. In JavaScript, every object has an internal property called [[Prototype]], which refers to its parent object or “prototype”. If a property or method is not found on the object itself, it is automatically looked up in its prototype.

When an object is used as a prototype for another object, the second object inherits all the properties and methods from the prototype. This allows for code reuse and the creation of object hierarchies.

The main difference between prototypical inheritance and classical inheritance is the way inheritance is achieved. In classical inheritance, classes are defined, and objects are instances of these classes. In prototypical inheritance, objects are used as prototypes for other objects directly, without the need for classes.

8. What are ES6 classes? How do they differ from function constructors?

ES6 classes are a syntactic sugar over the existing prototype-based inheritance model in JavaScript. They provide a more familiar class-based syntax for creating objects and defining their behavior.

Here’s an example of an ES6 class and its equivalent using a function constructor:

ES6 class:

JavaScript
class Person {
  constructor(name) {
    this.name = name;
  }

  sayHello() {
    console.log(`Hello, my name is ${this.name}.`);
  }
}

const john = new Person("John");
john.sayHello();

Function constructor:

JavaScript
function Person(name) {
  this.name = name;
}

Person.prototype.sayHello = function () {
  console.log("Hello, my name is " + this.name + ".");
};

var john = new Person("John");
john.sayHello();

Both the ES6 class and the function constructor achieve the same result. However, the class syntax provides a more intuitive and concise way to define classes and their methods, making the code easier to read and maintain.

9. What are the differences between ‘rest’ and ‘spread’ syntax?

The ‘rest’ and ‘spread’ syntax are two features introduced in ES6 that use the same ... notation but serve different purposes:

Rest Syntax: It allows gathering multiple elements into an array.

Example:

JavaScript
function sum(...numbers) {
  return numbers.reduce((acc, curr) => acc + curr, 0);
}

console.log(sum(1, 2, 3, 4)); // Output: 10

In this example, the rest syntax (...numbers) gathers all the arguments passed to the sum function into an array called numbers.

Spread Syntax: It allows expanding an array or iterable into individual elements.

Example:

JavaScript
const numbers = [1, 2, 3, 4];
console.log(...numbers); // Output: 1 2 3 4

const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const mergedArray = [...arr1, ...arr2];
console.log(mergedArray); // Output: [1, 2, 3, 4, 5, 6]

In the first example, the spread syntax is used to expand the numbers array into individual elements when passed to console.log(). It prints each element separately.

In the second example, the spread syntax is used to merge two arrays (arr1 and arr2) into a new array called mergedArray.

10. How does ‘destructuring assignment’ work?

Destructuring assignment is a feature in JavaScript that allows extracting values from objects or arrays into distinct variables, making it easier to access and work with the data.

Example using object destructuring:

JavaScript
const person = {
  name: "John",
  age: 30,
  city: "New York",
};

const { name, age, city } = person;
console.log(name, age, city); // Output: John 30 New York

In this example, the object person has properties name, age, and city. By using object destructuring, we can extract those properties into separate variables with the same names as the properties.

Example using array destructuring:

JavaScript
const numbers = [1, 2, 3, 4];
const [first, second, ...rest] = numbers;
console.log(first, second, rest); // Output: 1 2 [3, 4]

In this example, the array numbers contains elements [1, 2, 3, 4]. Using array destructuring, we can assign the first element to the variable first, the second element to second, and the rest of the elements to the array rest.

11. What are JavaScript Symbols? How and why would you use them?

JavaScript Symbols are a new primitive type introduced in ES6. They are unique and immutable, meaning that each Symbol value is distinct and cannot be changed.

Symbols are often used as property keys for object properties to ensure uniqueness and avoid naming conflicts. They can also be used to define well-known symbols or create private members in objects.

Example:

JavaScript
const sym1 = Symbol("description");
const sym2 = Symbol("description");

console.log(sym1 === sym2); // Output: false

const obj = {
  [sym1]: "value",
};

console.log(obj[sym1]); // Output: "value"

In this example, two symbols sym1 and sym2 are created with the same description. However, they are distinct values, and sym1 === sym2 returns false.

The symbol sym1 is used as a property key in the object obj, allowing access to the associated value using bracket notation (obj[sym1]).

12. How does the ‘this’ keyword work in JavaScript? How is it different in arrow functions? give code example

In JavaScript, the this keyword refers to the context in which a function is executed. It can behave differently based on how the function is called.

In a regular function, the value of this is determined by how the function is invoked. It can vary based on the function’s execution context, whether it is called as a method, as a constructor, or with the call or apply methods.

Example:

JavaScript
function greet() {
  console

.log(`Hello, ${this.name}!`);
}

const person = {
  name: "John",
  greet: greet,
};

person.greet(); // Output: "Hello, John!"

In this example, this inside the greet function refers to the person object because the function is called as a method of person.

Example:

JavaScript
const person = {
  name: "John",
  greet: function () {
    setTimeout(() => {
      console.log(`Hello, ${this.name}!`);
    }, 1000);
  },
};

person.greet(); // Output: "Hello, John!"

In this example, the arrow function inside the setTimeout function retains the this value of the greet method, which is the person object. Therefore, it correctly accesses the name property and prints "Hello, John!" after a delay of 1 second.

13. What is a pure function in JavaScript? give code example

A pure function in JavaScript is a function that always produces the same output for the same input and has no side effects. It does not modify any external state or rely on external mutable data.

Pure functions have the following characteristics:

  • The return value solely depends on the function’s arguments.
  • The function does not modify any mutable state or variables outside its scope.
  • The function does not perform any I/O operations or produce side effects.

Example of a pure function:

JavaScript
function add(a, b) {
  return a + b;
}

console.log(add(3, 5)); // Output: 8
console.log(add(3, 5)); // Output: 8 (same output for the same input)

In this example, the add function takes two arguments and returns their sum. It does not rely on any external state and consistently produces the same output for the same input. There are no side effects or modifications to any variables outside its scope.

14. What are the different ways to handle asynchronous operations in JavaScript?

JavaScript provides several ways to handle asynchronous operations:

  1. Callbacks: Callback functions are passed as arguments to asynchronous functions and called when the operation completes or an error occurs.

Example:

JavaScript
function fetchData(callback) {
  // Asynchronous operation
  setTimeout(function () {
    callback(null, "Data");
  }, 1000);
}

fetchData(function (err, data) {
  if (err) {
    console.error("Error:", err);
  } else {
    console.log("Data:", data);
  }
});
  1. Promises: Promises provide a more structured approach to handle asynchronous operations. They represent the eventual completion or failure of an asynchronous operation and allow chaining of multiple operations.

Example:

JavaScript
function fetchData() {
  return new Promise(function (resolve, reject) {
    // Asynchronous operation
    setTimeout(function () {
      resolve("Data");
    }, 1000);
  });
}

fetchData()
  .then(function (data) {
    console.log("Data:", data);
  })
  .catch(function (err) {
    console.error("Error:", err);
  });
  1. Async/await: Async/await is a syntactic sugar on top of Promises. It allows writing asynchronous code in a synchronous-like manner, making it easier to read and understand.

Example:

JavaScript
async function fetchData() {
  return new Promise(function (resolve, reject) {
    // Asynchronous operation
    setTimeout(function () {
      resolve("Data");
    }, 1000);
  });
}

async function getData() {
  try {
    const data = await fetchData();
    console.log("Data:", data);
  } catch (err) {
    console.error("Error:", err);
  }
}

getData();
  1. Observables: Observables provide a powerful way to handle asynchronous and event-based programming. They allow subscribing to a stream of events or data and provide a wide range of operators to transform and manipulate the data.

Example using RxJS library:

JavaScript
import { Observable } from 'rxjs';

function fetchData() {
  return new Observable(function (observer) {
    // Asynchronous operation
    setTimeout(function () {
      observer.next("Data");
      observer.complete();
    }, 1000);
  });
}

fetchData().subscribe({
  next: function (data) {
    console.log("Data:", data);
  },
  error: function (err) {
    console.error("Error:", err);
  },
  complete: function () {
    console.log("Completed");
  },
});

15. Explain the differences between ‘map’, ‘forEach’, and ‘reduce’.

map, forEach, and reduce are methods available for arrays in JavaScript to iterate over their elements and perform operations. Here are the differences between them:

  • forEach: It executes a provided function once for each element in the array and does not return a new array. It is primarily used for its side effects.

Example:

JavaScript
const array = [1, 2, 3];
array.forEach(function (element) {
  console.log(element);
});
  • map: It creates a new array by calling a provided function on each element of the original array. It returns a new array with the transformed values.

Example:

JavaScript
const array = [1, 2, 3];
const mappedArray = array.map(function (element) {
  return element * 2;
});
console.log(mappedArray); // Output: [2, 4, 6]
  • reduce: It reduces the array to a single value by applying a provided function that accumulates the result. It takes an initial value and performs the reduction operation from left to right.

Example:

JavaScript
const array = [1, 2, 3];
const sum = array.reduce(function (accumulator, element) {
  return accumulator + element;
}, 0);
console.log(sum); // Output: 6

The main differences between map and forEach are that map returns a new array, whereas forEach does not. Additionally, reduce reduces the array to a single value by iteratively applying the provided function and accumulating the result.

16. What is the difference between ‘null’ and ‘undefined’?

Propertynullundefined
1.It is an assignment value that represents the absence of an object valueIt is a variable that has been declared but has not been assigned a value
2.Must be assigned explicitly to a variableAutomatically assigned by JavaScript
3.Represents an intentional absence of any object valueRepresents an unintentional absence of value
4.typeof null returns “object”typeof undefined returns “undefined”
5.Can be assigned to a variableCannot be assigned explicitly

17. What are JavaScript Observables and how do they differ from Promises?

JavaScript Observables are a way to handle asynchronous and event-based programming, similar to Promises. They represent a stream of values or events that can be observed by subscribing to them.

Here’s an example using the RxJS library to create an Observable:

JavaScript
import { Observable } from 'rxjs';

const observable = new Observable(function (observer) {
  observer.next("Data 1");
  observer.next("Data 2");
  observer.next("Data 3");
  observer.complete();
});

observable.subscribe({
  next: function (data) {
    console.log("Data:", data);
  },
  error: function (err) {
    console.error("Error:", err);
  },
  complete: function () {
    console.log("Completed");
  },
});

In this example, an Observable is created that emits three values ("Data 1", "Data 2", "Data 3") and then completes. The subscribe method is used to observe the emitted values. The subscriber object defines three handlers: next to handle each emitted value, error to handle any errors, and complete to handle the completion of the Observable.

18. What is a JavaScript Proxy and what is it used for?

A JavaScript Proxy is an object that wraps another object and intercepts fundamental operations, allowing custom behavior to be defined for these operations. Proxies enable the creation of objects with modified behavior or enhanced functionality.

Example:

JavaScript
const target = {
  name: "John",
  age: 30,
};

const handler = {
  get: function (target, prop) {
    console.log(`Accessed property: ${prop}`);
    return target[prop];
  },
  set: function (target, prop, value) {
    console.log(`Set property: ${prop} = ${value}`);
    target[prop] = value;
    return true;
  },
};

const proxy = new Proxy(target, handler);

console.log(proxy.name); // Output: "John" (get operation intercepted)
proxy.age = 31; // Output: "Set property: age = 31" (set operation intercepted)
console.log(proxy.age); // Output: 31 (get operation intercepted)

In this example, a Proxy is created for the target object. The handler object defines the behavior for the get and set operations. When a property is accessed (proxy.name) or set (proxy.age = 31), the corresponding handler methods are invoked, allowing custom logic to be executed.

19. Explain the concept of ‘memoization’ in JavaScript.

Memoization is a technique used to optimize functions by caching the results of expensive function calls and returning the cached result when the same inputs occur again. It helps to avoid redundant computations and improve performance.

Example:

JavaScript
function fibonacci(n, cache = {}) {
  if (n in cache) {
    return cache[n];
  }

  if (n <= 1) {
    return n;
  }

  const result = fibonacci(n - 1, cache) + fibonacci(n - 2, cache);
  cache[n] = result;
  return result;
}

console.log(fibonacci(10)); // Output: 55

In this example, the fibonacci function calculates the Fibonacci sequence recursively. The cache object is used to store previously computed values. When the function is called with the same n value, it checks if the result is already in the cache and returns it directly, avoiding redundant calculations.

20. What is currying in JavaScript and why might you use this technique?

Currying is a technique in JavaScript that involves transforming a function with multiple arguments into a sequence of functions, each taking a single argument. It allows partial application of a function by fixing some of its arguments in advance.

The benefits of currying include:

  • Increased reusability and flexibility of functions.
  • Facilitates function composition.
  • Enables the creation of specialized functions from more general ones.

Example:

JavaScript
function add(a) {
  return function (b) {
    return a + b;
  };
}

const addFive = add(5);
console.log(addFive(3)); // Output: 8
console.log(addFive(7)); // Output: 12

In this example, the add function takes a single argument a and returns an inner function that takes another argument b. The inner function adds a and b together. By calling add(5), we create a new function addFive that adds 5 to its argument. This allows us to reuse the addFive function multiple times with different values of b.

21. What is function composition in JavaScript?

Function composition is a technique in JavaScript where multiple functions are combined to create a new function that executes the composed functions in a specific order. The output of one function becomes the input of the next function, forming a pipeline of data transformations.

Example:

JavaScript
function add(a, b) {
  return a + b;
}

function multiply(a, b) {
  return a * b;
}

function subtract(a, b) {
  return a - b;
}

const compose = (...functions) => (initialValue) =>
  functions.reduce((acc, fn) => fn(acc), initialValue);

const calculation = compose(
  (value) => add(value, 5),
  (value) => multiply(value, 2),
  (value) => subtract(value, 10)
);

console.log(calculation(20)); // Output: 55

In this example, the functions add, multiply, and subtract perform basic arithmetic operations. The compose function takes an array of functions and returns a new function that applies each function in the array to an initial value. The result is a composition of functions that calculates 20 + 5, then multiplies the result by 2, and finally subtracts 10, resulting in 55.

22. What is the purpose of JavaScript’s built-in ‘apply’, ‘call’, and ‘bind’ methods?

The built-in methods apply, call, and bind in JavaScript are used to control the value of this in a function and to invoke functions with a specified this value.

  • apply: Calls a function with a given this value and an array-like or iterable object as the arguments.

Example:

JavaScript
function greet(greeting) {
  console.log(`${greeting}, ${this.name}!`);
}

const person = {
  name: "John",
};

greet.apply(person, ["Hello"]); // Output: "Hello, John!"
  • call: Calls a function with a given this value and individual arguments.

Example:

JavaScript
function greet(greeting) {
  console.log(`${greeting}, ${this.name}!`);
}

const person = {
  name: "John",
};

greet.call(person, "Hello"); // Output: "Hello, John!"
  • bind: Returns a new function with a given this value and pre-filled arguments.

Example:

JavaScript
function greet(greeting) {
  console.log(`${greeting}, ${this.name}!`);
}

const person = {
  name: "John",
};

const greetPerson = greet.bind(person);
greetPerson("Hello"); // Output: "Hello, John!"

In all three cases, the methods allow explicit control over the value of this inside a function. apply and call invoke the function immediately, while bind returns a new function that can be called later.

23. What are JavaScript Generators and how do they work?

JavaScript Generators are special functions that can be paused and resumed during their execution. They provide a way to generate a sequence of values over time, allowing for more efficient memory usage and better control flow.

Generators are defined using the function* syntax and use the yield keyword to pause the function and return a value. The generator function can be iterated using a for...of loop or by manually calling the next method on the generator object.

Example:

JavaScript
function* countTo(limit) {
  for (let i = 1; i <= limit; i++) {
    yield i;
  }
}

const generator = countTo(5);

console.log(generator.next()); // Output: { value: 1, done: false }
console.log(generator.next()); // Output: { value: 2, done: false }
console.log(generator.next()); // Output: { value: 3, done: false }
console.log(generator.next()); // Output: { value: 4, done: false }
console.log(generator.next()); // Output: { value: 5, done: false }
console.log(generator.next()); // Output: { value: undefined, done: true }

In this example, the countTo generator function generates a sequence of numbers from 1 to the specified limit. Each time the yield statement is encountered, the function pauses and returns the current value. The generator object is created by calling the generator function, and the next method is used to iterate through the sequence of values.

24. What is the difference between JavaScript’s window, document, and screen objects?

  • window: The window object represents the browser window or tab that contains the JavaScript code. It provides properties and methods to interact with the browser window, handle events, set timers, and manage the document.
  • document: The document object represents the web page loaded in the browser window. It provides properties and methods to access and manipulate the elements, content, and structure of the document.
  • screen: The screen object represents the user’s screen or display. It provides properties to get information about the user’s screen, such as width, height, pixel density, and color depth.

25. What are JavaScript decorators and what are they used for?

JavaScript decorators are a feature introduced in ES2016/ES7 that allow modifying the behavior of classes, methods, and properties using a special syntax. They are essentially higher-order functions that wrap or annotate the target with additional functionality.

Decorators are prefixed with the @ symbol and can be used to implement cross-cutting concerns, such as logging, caching, validation, or authorization.

Example:

JavaScript
function log(target, name, descriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args) {
    console.log(`Calling ${name} with arguments:`, args);
    return originalMethod.apply(this, args);
  };

  return descriptor;
}

class Calculator {
  @log
  add(a, b) {
    return a + b;
  }
}

const calculator = new Calculator();
console.log(calculator.add(2, 3)); // Output: "Calling add with arguments: [2, 3]" 5

In this example, the log decorator is defined as a function that modifies the behavior of the add method in the Calculator class. It logs the method name and arguments before invoking the original method.

26. How does JavaScript’s ‘try-catch-finally’ construct work?

The try-catch-finally construct in JavaScript allows handling exceptions and executing code in the presence or absence of exceptions. It provides a way to handle errors and gracefully recover from them.

The try block contains the code that may throw an exception. If an exception occurs within the try block, the control is transferred to the corresponding catch block. The catch block handles the exception by specifying an identifier to hold the error object.

The finally block is optional and always executes, regardless of whether an exception occurred or not. It is commonly used to perform cleanup tasks, such as closing resources or releasing memory, regardless of the outcome of the try-catch block.

Example:

JavaScript
try {
  // Code that may throw an exception
  throw new Error("Something went wrong!");
} catch (error) {
  // Handling the exception
  console.error(error);
} finally {
  // Cleanup or other tasks
  console.log("Finally block executed");
}

In this example, the try block intentionally throws an Error object. The catch block captures the error and logs it to the console. Finally, the finally block is executed, printing the message “Finally block executed” to the console.

27. What are the principles of Object-Oriented Programming (OOP) in JavaScript?

The principles of Object-Oriented Programming (OOP) in JavaScript are:

  1. Encapsulation: The bundling of related data and methods into objects, and the protection of data from direct access by using access modifiers.
  2. Inheritance: The ability of objects to inherit properties and methods from a parent object, allowing code reuse and creating hierarchies of objects.
  3. Polymorphism: The ability of objects to take on multiple forms and exhibit different behavior based on their type or the context in which they are used.
  4. Abstraction: The process of simplifying complex systems by breaking them down into smaller, more manageable parts. It involves hiding unnecessary details and exposing only the essential information.
  5. Composition: The building of complex objects or behaviors by combining simpler objects or behaviors. It promotes code reuse and modular design.

28. What is the purpose of the ‘use strict’ directive in JavaScript?

The 'use strict' directive is used to enable strict mode in JavaScript. It is a way to opt into a restricted variant of JavaScript that enforces stricter rules and prevents certain common mistakes.

Enabling strict mode has several benefits:

  1. Variables must be declared with var, let, or const. Implicit global variables are not allowed, reducing the risk of accidental global scope pollution.
  2. Assigning a value to an undeclared variable, deleting variables or functions, or using restricted keywords (such as eval or arguments) raises an error.
  3. Duplicate parameter names in function declarations raise an error.
  4. this is undefined in functions that are not methods or constructors, preventing accidental usage of the global object as the context.

29. What are JavaScript mixins? How are they used and what are some potential pitfalls?

JavaScript mixins are a way to enhance the functionality of an object by combining multiple sets of properties and methods from different sources. Mixins provide a mechanism for code reuse and composition, allowing objects to inherit behavior from multiple mixins.

A mixin is typically an object that contains a set of methods or properties. These methods or properties can be copied or merged into the target object using various techniques such as Object.assign(), Object.setPrototypeOf(), or by extending the object with a mixin class.

Example:

JavaScript
const sayHelloMixin = {
  sayHello() {
    console.log(`Hello, ${this.name}!`);
  },
};

class Person {
  constructor(name) {
    this.name = name;
  }
}

Object.assign(Person.prototype, sayHelloMixin);

const john = new Person("John");
john.sayHello(); // Output: "Hello, John!"

In this example, the sayHelloMixin object contains the sayHello method. The method is mixed into the Person class by assigning it to the Person.prototype object using Object.assign(). As a result, instances of the Person class can now invoke the sayHello method.

Potential pitfalls of mixins include:

  • Naming conflicts: If two mixins define methods or properties with the same name, there can be conflicts and unintended behavior.
  • Dependency management: Managing dependencies between mixins can become complex, especially when multiple mixins depend on each other or override the same methods.
  • Inheritance limitations: Mixins do not provide true inheritance, as they copy or merge properties and methods into an object rather than creating a prototype chain. This can lead to limitations in method overriding or accessing the mixin’s state.

30. What are the differences between ES5 and ES6, and what new features were introduced in ES6?

ES5 (ECMAScript 5) and ES6 (ECMAScript 2015, also known as ES2015) are two versions of the ECMAScript standard, which is the specification for JavaScript.

Differences between ES5 and ES6:

  1. Syntax enhancements: ES6 introduces new syntax features like let and const for block-scoped variables, arrow functions, template literals, and destructuring assignment.
  2. Classes: ES6 introduces the class syntax for defining classes, making it easier to create objects with inheritance and encapsulation.
  3. Modules: ES6 introduces native support for modules with the import and export keywords, enabling better code organization and dependency management.
  4. Arrow functions: ES6 arrow functions provide a concise syntax and lexical scoping for defining functions.
  5. Promises: ES6 introduces native support for Promises, simplifying asynchronous programming and providing better error handling and composition of asynchronous operations.
  6. Generators: ES6 introduces generator functions that can pause and resume their execution, allowing for more efficient asynchronous programming and iterators.
  7. Enhanced object literals: ES6 provides enhancements to object literals, such as shorthand syntax for defining methods, computed property names, and property value shorthands.
  8. Iterators and for…of loop: ES6 introduces the Symbol.iterator interface and the for...of loop, making it easier to iterate over data structures like arrays, strings, and custom iterables.

Coding Questions

1. Find the Length of a String

JavaScript
function findStringLength(str) {
  return str.length;
}

2. Reverse a String

JavaScript
function reverseString(str) {
  return str.split('').reverse().join('');
}

3. Factorialize a Number

JavaScript
function factorialize(num) {
  if (num === 0 || num === 1) {
    return 1;
  }

  let result = 1;
  for (let i = 2; i <= num; i++) {
    result *= i;
  }

  return result;
}

4. Check for Palindromes

JavaScript
function isPalindrome(str) {
  str = str.toLowerCase().replace(/[^a-z0-9]/g, '');
  const reversedStr = str.split('').reverse().join('');

  return str === reversedStr;
}

5. Find the Longest Word in a String

JavaScript
function findLongestWord(str) {
  const words = str.split(' ');
  let longestWord = '';

  for (let i = 0; i < words.length; i++) {
    if (words[i].length > longestWord.length) {
      longestWord = words[i];
    }
  }

  return longestWord.length;
}

6. Title Case a Sentence

JavaScript
function titleCase(str) {
  const words = str.toLowerCase().split(' ');

  for (let i = 0; i < words.length; i++) {
    words[i] = words[i][0].toUpperCase() + words[i].slice(1);
  }

  return words.join(' ');
}

7. Return Largest Numbers in Arrays

JavaScript
function largestNumbers(arr) {
  const largestArr = [];

  for (let i = 0; i < arr.length; i++) {
    let largestNum = arr[i][0];

    for (let j = 1; j < arr[i].length; j++) {
      if (arr[i][j] > largestNum) {
        largestNum = arr[i][j];
      }
    }

    largestArr.push(largestNum);
  }

  return largestArr;
}

8. Confirm the Ending

JavaScript
function confirmEnding(str, target) {
  return str.endsWith(target);
}

9. Finders Keepers

JavaScript
function findElement(arr, func) {
  for (let i = 0; i < arr.length; i++) {
    if (func(arr[i])) {
      return arr[i];
    }
  }

  return undefined;
}

10. Arguments Optional

JavaScript
function addTogether(a, b) {
  if (typeof a !== 'number') {
    return undefined;
  }

  if (b === undefined) {
    return function (c) {
      if (typeof c !== 'number') {
        return undefined;
      }
      return a + c;
    };
  }

  if (typeof b !== 'number') {
    return undefined;
  }

  return a + b;
}

MCQ Questions

1. What is JavaScript?

a) A scripting language used for client-side web development
b) A programming language used for server-side application development
c) A markup language used for designing web pages
d) A database management language

Answer: a) A scripting language used for client-side web development

2. What is the typeof operator used for in JavaScript?

a) Determining the type of a variable
b) Converting a value to a specific type
c) Checking if a variable is defined
d) Assigning a value to a variable

Answer: a) Determining the type of a variable

3. What is the output of the following code snippet?

console.log(1 + "2" + "3");

a) 123
b) 15
c) “123”
d) “15”

Answer: c) “123”

4. Which keyword is used to declare a variable in JavaScript?

a) var
b) let
c) const
d) All of the above

Answer: d) All of the above

5. What is the result of the following expression?

JavaScript
typeof NaN

a) “number”
b) “NaN”
c) “undefined”
d) “NaN”

Answer: a) “number”

6. Which of the following is not a valid JavaScript data type?

a) boolean
b) number
c) character
d) string

Answer: c) character

7. What is the result of the following expression?

JavaScript
"5" - 2

a) 3
b) “3”
c) 7
d) “7”

Answer: a) 3

8. What is the purpose of the “this” keyword in JavaScript?

a) It refers to the current HTML element
b) It refers to the current JavaScript file
c) It refers to the current function
d) It refers to the current object

Answer: d) It refers to the current object

9. What is the output of the following code snippet?

JavaScript
console.log(2 + 3 + "5");

a) 10
b) “55”
c) “235”
d) 25

Answer: b) “55”

10. Which of the following is a correct way to define a function in JavaScript?

a) function = myFunction() {}
b) function myFunction() {}
c) var myFunction() = function() {}
d) var myFunction = () => {}

Answer: b) function myFunction() {}

11. What is the result of the following expression?

JavaScript
3 > 2 > 1

a) true
b) false
c) SyntaxError
d) TypeError

Answer: b) false

12. How do you comment a single line in JavaScript?

a) // This is a comment
b) / This is a comment
c) /* This is a comment */
d) % This is a comment %

Answer: a) // This is a comment

13. What is the output of the following code snippet?

JavaScript
console.log("2" * "3");

a) 5
b) 6
c) “6”
d) “23”

Answer: b) 6

14. Which of the following is not a JavaScript loop statement?

a) for
b) while
c) loop
d) do…while

Answer: c) loop

15. What is the result of the following expression?

JavaScript
null == undefined

a) true
b) false
c) SyntaxError
d) TypeError

Answer: a) true

16. How do you declare a JavaScript array?

a) var arr = [];
b) var arr = new Array();
c) Both a and b are correct
d) None of the above

Answer: c) Both a and b are correct

17. What is the output of the following code snippet?

JavaScript
console.log(10 === "10");

a) true
b) false
c) SyntaxError
d) TypeError

Answer: b) false

18. What is the purpose of the “break” statement in JavaScript?

a) It terminates the current loop or switch statement
b) It skips the current iteration of a loop and continues with the next iteration
c) It defines a block of code to be executed if a specific condition is true
d) It defines a function in JavaScript

Answer: a) It terminates the current loop or switch statement

19. What is the output of the following code snippet?

JavaScript
console.log("Hello" + 5);

a) “Hello5”
b) “Hello”
c) 10
d) SyntaxError

Answer: a) “Hello5”

20. Which of the following is not a valid JavaScript comparison operator?

  • a) ==
  • b) !=
  • c) <=
  • d) ><

Answer: d) ><

21. What is the output of the following code snippet?

JavaScript
console.log(typeof typeof 1);

a) “number”
b) “string”
c) “object”
d) “undefined”

Answer: b) “string”

22. How do you access the length of a JavaScript array?

a) arr.length()
b) arr.length
c) arr.size()
d) arr.size

Answer: b) arr.length

23. What is the result of the following expression?

JavaScript
true + true

a) 2
b) true
c) false
d) NaN

Answer: a) 2

24. How do you check if a variable is an array in JavaScript?

a) typeof arr === “array”
b) arr.isArray()
c) Array.isArray(arr)
d) arr instanceof Array

Answer: c) Array.isArray(arr)

25. What is the output of the following code snippet?

JavaScript
console.log("5" + 2 - 1);

a) 52
b) “521”
c) 6
d) NaN

Answer: d) NaN

26. Which of the following is a correct way to create a JavaScript object?

a) var obj = new Object();
b) var obj = {};
c) Both a and b are correct
d) None of the above

Answer: c) Both a and b are correct

27. What is the output of the following code snippet?

JavaScript
console.log(1 + true);

a) 1
b) true
c) 2
d)NaN

Answer: c) 2

28. How do you convert a string to a number in JavaScript?

a) parseInt(str)
b) parseFloat(str)
c) Number(str)
d) All of the above

Answer: d) All of the above

29. What is the output of the following code snippet?

JavaScript
console.log(10 % 3);

a) 1
b) 3
c) 0
d) 10

Answer: a) 1

30. What is the purpose of the “continue” statement in JavaScript?

a) It terminates the current loop or switch statement
b) It skips the current iteration of a loop and continues with the next iteration
c) It defines a block of code to be executed if a specific condition is true
d) It defines a function in JavaScript

Answer: b) It skips the current iteration of a loop and continues with the next iteration

31. What is the output of the following code snippet?

JavaScript
console.log("5" - 2);

a) 3
b) “3”
c) 7
d) “7”

Answer: a) 3

32. How do you declare a JavaScript function?

a) function myFunction() {}
b) var myFunction = function() {}
c) () => {}
d) All of the above

Answer: d) All of the above

33. What is the output of the following code snippet?

JavaScript
console.log(10 / 0);

a) 0
b) Infinity
c) NaN
d) SyntaxError

Answer: b) Infinity

34. What is the purpose of the “typeof” operator in JavaScript?

a) It returns the data type of a variable
b) It checks if a variable is defined
c) It converts a value to a specific type
d) It assigns a value to a variable

Answer: a) It returns the data type of a variable

35. What is the output of the following code snippet?

JavaScript
console.log(10 == "10");

a) true
b) false
c) SyntaxError
d) TypeError

Answer: a) true

36. How do you concatenate two strings in JavaScript?

a) str1.add(str2)
b) str1.concat(str2)
c) str1 + str2
d) All of the above

Answer: c) str1 + str2

37. What is the output of the following code snippet?

JavaScript
console.log(10 > 9 > 8);

a) true
b) false
c) SyntaxError
d) TypeError

Answer: b) false

38. How do you round a number to the nearest integer in JavaScript?

a) Math.floor(num)
b) Math.ceil(num)
c) Math.round(num)
d) All of the above

Answer: c) Math.round(num)

39. What is the output of the following code snippet?

JavaScript
console.log(0.1 + 0.2 == 0.3);

a) true
b) false
c) SyntaxError
d) TypeError

Answer: b) false

40. How do you convert a number to a string in JavaScript?

a) num.toString()
b) String(num)
c) “” + num
d) All of the above

Answer: d) All of the above

41. What is the output of the following code snippet?

JavaScript
console.log(Math.max(1, 2, 3));

a) 1
b) 2
c) 3
d) SyntaxError

Answer: c) 3

42. How do you get the current date and time in JavaScript?

a) Date.now()
b) new Date()
c) getCurrentDate()
d) All of the above

Answer: b) new Date()

43. What is the output of the following code snippet?

JavaScript
console.log(10 ** 2);

a) 10
b) 20
c) 100
d) 102

Answer: c) 100

44. How do you convert a string to uppercase in JavaScript?

a) str.toUpperCase()
b) str.lowerCase()
c) str.toUpper()
d) All of the above

Answer: a) str.toUpperCase()

45. What is the output of the following code snippet?

JavaScript
console.log(Math.floor(4.7));

a) 4
b) 5
c) 4.7
d) SyntaxError

Answer: a) 4

46. How do you check if a string contains a specific substring in JavaScript?

a) str.includes(substring)
b) str.contains(substring)
c) str.indexOf(substring)
d) All of the above

Answer: a) str.includes(substring)

47. What is the output of the following code snippet?

JavaScript
console.log(typeof [1, 2, 3]);

a) “array”
b) “object”
c) “undefined”
d) “null”

Answer: b) “object”

48. How do you convert a string to lowercase in JavaScript?

a) str.toLowerCase()
b) str.upperCase()
c) str.toLower()
d) All of the above

Answer: a) str.toLowerCase()

49. What is the output of the following code snippet?

JavaScript