52 Frontend Interview Questions - JavaScript

m_midas

Yan Levin

Posted on August 12, 2023

52 Frontend Interview Questions - JavaScript

Introduction

A large number of beginner and experienced developers have started to encounter and notice a problem with job searching. Indeed, the level of competition in the market has become much higher than it was 2-3 years ago.

The best thing to do in the current reality is to keep learning.
In this article, I have compiled 52 questions in a "question:answer" format for frontend developers that I have come across during interviews. The questions are mainly geared towards Junior level and partially towards Middle level.

P.S. Despite the fact that most of the questions are aimed at the Junior level, by preparing for these questions and thoroughly studying the topics, I was able to secure a job as a Middle Frontend Developer.

1. What data types exist in JavaScript?

  1. Number - Numbers
  2. String - Strings
  3. Boolean - Boolean type, true or false
  4. Object - JavaScript object
  5. null - a special value that represents "nothing", "empty", or "unknown value".
  6. undefined - "value has not been assigned". This type is assigned if a variable is declared but has no assigned value.
  7. Symbol - a unique and immutable data type that can be used as an identifier for object properties.
  8. BigInt - used for creating large numbers.

const bigInt = 1234567890123456789012345678901234567890n;

Learn more

2. What is the difference between "==" and "==="?

The operator "==" checks for abstract equality, while "===" checks for strict equality.
In other words, the "==" operator performs necessary type conversions before comparison, whereas "===" does not perform type conversion. Therefore, if two values are not of the same type, it will return false when using the "===" operator.

Learn more

3. What are the ways to declare a variable?

There are 4 ways to declare a variable:

  foo = 123; 
  var foo = 123; 
  let a = 123; 
  const a = 123; 
Enter fullscreen mode Exit fullscreen mode

Declaring a variable using the "var" keyword is similar to the first method. Variables declared this way have global or function scope and lack block scope, which is a disadvantage.
"let" and "const" are preferable ways to declare variables. They have block scope, meaning that a variable declared inside, for example, a function, will not be visible outside of that function. "const" variables are immutable, but if it's an object, you can change its properties, and if it's an array, you can modify and add elements.

Learn more

4. What is the difference between null and undefined?

Both options represent an empty value. If we initialize a variable but don't assign a value to it, it will be assigned a special marker - undefined. Null is assigned manually.

Null is a special value that represents "nothing," "empty," or "unknown value." If we need to clear the value of a variable, we set foo = null.

Learn more

5. Arrow functions and the differences from regular functions.

  1. Arrow functions cannot use the arguments object.
  2. They have a different syntax.
  3. Arrow functions do not have their own this context. When referencing this, an arrow function takes the context from the surrounding scope.
  4. Arrow functions cannot be used as constructor functions. In other words, they cannot be invoked with the new keyword.

Learn more

6. What is a closure and why are they needed?

A closure is a function along with all the external variables that it has access to. For example, there is a function that has a nested function which will close over and retain the variables from its parent.

function parent() { 
    const a = 5; 
    return function child() { 
        console.log(5); // child closes over the variable 'a'; 
    } 
}
Enter fullscreen mode Exit fullscreen mode

Learn more

7. What are template literals?

Template literals are enclosed in backticks () and allow for multiline strings. They also allow for embedding expressions within them.

const name = 'John';
const text = `User's name is ${name}`;

console.log(text) // User's name is John
Enter fullscreen mode Exit fullscreen mode

Learn more

8. What are Set and Map?

Map is a collection, a data structure that operates on the principle of key-value pairs, similar to Objects. However, the main difference between Map and Object is that Map allows the use of keys of any type.
Set is a type of collection without keys, an array where each value can only appear once. Set stores unique values within itself.

Learn more

9. How to check for the presence of a property in an object?

The first way is to use the hasOwnProperty function, which is available for every object.
The second way is to use the in operator. However, when using the in operator, caution must be exercised as it checks all prototypes in the chain.

const obj = {
  year: 2023,
  name: "John"
}

console.log(obj.hasOwnProperty("year")) // true
console.log("year" in obj) // true
console.log("ye" in obj) // false
Enter fullscreen mode Exit fullscreen mode

Learn more

10. How to access an object property?

The first way is static, using dot notation: obj.a.
The second way is dynamic, using square brackets: obj['a'].

const obj = {
  year: 2023,
  name: "John"
}

console.log(obj['year']) // 2023
console.log(obj.name) // John
Enter fullscreen mode Exit fullscreen mode

Learn more

11. What are the main methods for working with arrays?

  • forEach - an iterative method for looping through the array, does not return anything. It offers a more elegant alternative to a regular for loop.
  • filter(callback, [args]) - a method for filtering an array using a provided function. It creates a new array that includes only the elements from the original array for which the callback(item, i, arr) function returns true.
  • map(callback, [args]) - a method for transforming an array. It creates a new array that consists of the results of calling the callback(item, i, arr) function for each element of the array.
  • reduce(callback, [initValue]) - a method for sequentially processing each element of the array while maintaining an intermediate result.

Learn more

12. What are the ways to create an object?

Using a constructor function:

function User(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
}
const user = new User('John', 'Johnson');
console.log(user); // { firstName: 'John', lastName: 'Johnson' }
Enter fullscreen mode Exit fullscreen mode

Using object literal notation:

const user = {
  firstName: 'John',
  lastName: 'Johnson'
};
Enter fullscreen mode Exit fullscreen mode

Using a class:

class User {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }
}
const user = new User('John', 'Johnson');
console.log(user); // { firstName: 'John', lastName: 'Johnson' }
Enter fullscreen mode Exit fullscreen mode

Using the create function:

const user = Object.create({
  firstName: 'John',
  lastName: 'Johnson'
});
Enter fullscreen mode Exit fullscreen mode

13. What is a Promise?

A Promise is an object designed to work with asynchronous code. It maintains its own state. Initially, a Promise is in the pending state, then it transitions to the fulfilled state if the asynchronous code is executed successfully, or to the rejected state if an error occurs. A Promise accepts two callback functions:

  • onFulfilled, which is triggered when the Promise is fulfilled.
  • onRejected, which is triggered when the Promise is rejected.

The usage pattern is as follows:

  1. The code that needs to perform something asynchronously creates a Promise and returns it.
  2. The external code, upon receiving the Promise, passes the onFulfilled and onRejected callback functions to it.
  3. Upon completion of the process, the asynchronous code transitions the Promise to the fulfilled or rejected state, automatically invoking the corresponding callback function.

Learn more

14. What is async/await and how to use it?

async/await is a special syntax for working with Promises.
A function declared with the async syntax always returns a Promise.
The keyword await makes the JavaScript interpreter wait until the Promise on the right side of await is fulfilled before continuing the execution. It will then return the result, and the code execution will proceed. await cannot be used in regular functions.

Learn more

15. How to check if an object is an array?

To check whether an object is an array or not, you can use the Array.isArray() method. It takes an object as input and returns true if the object is an array, and false if it is not an array.

const obj1 = { person: 'John' }
const obj2 = new Array(2)
const obj3 = []

console.log(Array.isArray(obj1)) // false
console.log(Array.isArray(obj2)) // true
console.log(Array.isArray(obj3)) // true
Enter fullscreen mode Exit fullscreen mode

16. What is the purpose of the spread operator?

The spread operator (...) is used to unpack arrays or objects.
It allows you to expand elements that are iterable, such as arrays and strings.

  • It is used in functions where the expected number of arguments for a call is zero or more.
  • It is used in array literals or expressions.
  • It is used in object literals where the number of key-value pairs should be zero or more.
const date = [2000, 3, 7] 
const newArray = [...date] // [2000, 3, 7]
Enter fullscreen mode Exit fullscreen mode

Learn more

17. How to avoid reference dependency when copying an object?

If the object does not contain nested objects, for example:

const obj = {
 firstName: 'John',
 lastName: 'Johnson'
}
Enter fullscreen mode Exit fullscreen mode

In this case, you can use spread operator or Object.assign() method:

const copy = {...obj}
// or
const copy = Object.assign({}, obj)
Enter fullscreen mode Exit fullscreen mode

If the object contains nested objects:

const obj = {
    data: {
        id: 1
    }
}
Enter fullscreen mode Exit fullscreen mode

In this case, you need to perform a deep copy.
A workaround, though slower, is:

const copy = JSON.parse(JSON.stringify(obj))
Enter fullscreen mode Exit fullscreen mode

This method is suitable for objects without prototypes and functions.
Alternatively, you can use the lodash library's deepClone() function.

18. How to change the context of a function?

  1. Using the bind() method, which returns a new function with the bound context.
function foo() {
    return this
}
const obj = { name: 'John' }
const newFoo = foo.bind(obj)
console.log(newFoo()) // { name: 'John' }
Enter fullscreen mode Exit fullscreen mode
  1. Using call() and apply() methods. The main difference is that call() accepts a sequence of arguments, while apply() accepts an array of arguments as the second parameter.
function foo() {
    return this
}

const obj = { name: 'John' }
foo.call(obj, 'arg1', 'arg2') // { name: 'John' }
foo.apply(obj, ['arg1', 'arg2']) // { name: 'John' }
Enter fullscreen mode Exit fullscreen mode

19. What is a ternary operator?

A ternary operator is a shorthand notation for an if-else statement. The operator is represented by a question mark and a colon. It is called ternary because it is the only operator that takes three arguments.

Condition ? Expression_1 : Expression_2

num >= 10 ? 'more than 10' : 'less than 10'
// is equal to
if (num >= 10) {
    return 'more than or equal to 10'
}
return 'less than 10'
Enter fullscreen mode Exit fullscreen mode

Learn more

20. What is destructuring?

Destructuring is a syntax that allows us to unpack arrays and objects into multiple variables.

const arr = ['John', 'Johnson']
const [firstName, lastName] = arr
console.log(firstName, lastName) // John Johnson

OR

const obj = {
    firstName: 'John',
    lastName: 'Johnson'
}
const { firstName, lastName } = obj;
console.log(firstName, lastName) // John Johnson
Enter fullscreen mode Exit fullscreen mode

Learn more

21. What is the DOM?

DOM stands for Document Object Model. It is a representation of an HTML document as a tree of tags.
Example
Each node in the DOM tree is an object.

JS DOM

The basic elements of an HTML document are tags.
According to the Document Object Model (DOM), each HTML tag is an object. Nested tags are "children" of their parent element. The text inside a tag is also an object. All these objects are accessible using JavaScript, and we can use them to manipulate the page.

Learn more

22. What is the Event Loop?

Event loop - a mechanism that manages the execution of code. It handles event processing and task execution in the correct order. The main idea of the event loop is that JavaScript runs in a single-threaded environment but can handle asynchronous operations. When an asynchronous operation, such as a server request, completes, it puts the corresponding event into the event queue. The event loop works in a loop, processing these events in the order they arrive. It takes an event from the queue and passes it for execution. If the event contains a callback or a handler, it is invoked, and the code associated with that event is executed. The event loop also handles other tasks, such as timers and microtasks (Promise). It manages the execution order of all these tasks to ensure consistency and prevent the blocking of the main thread of code execution.

In short, the event loop in JavaScript manages asynchronous operations by handling events in the queue and executing the corresponding code in the correct order. This allows JavaScript to be responsive and effectively utilize its resources when working with asynchronous operations.

Event loop

I highly recommend watching the video at the link provided, as the topic is important and deserves a separate article.

Learn more

23. What is prototypal inheritance?

Every object in JavaScript has a property - a prototype. Methods and properties can be added to the prototype. Other objects can be created based on the prototype. The created object automatically inherits the methods and properties of its prototype. If a property is absent in the object, its search will be performed in the prototype.
Learn more

24. What is the Optional Chaining operator?

The Optional Chaining operator ?. stops the evaluation and returns undefined if the part after ?. is either undefined or null.

Let's consider a user object. Most users have an address user.address, with a street user.address.street, but some users have not provided an address. In such cases, the Optional Chaining operator can help us avoid an error when trying to access the user's street who hasn't specified one in their address.

const user = {};

console.log(user.address.street) // Error!
console.log(user?.address?.street) // undefined. No Error
Enter fullscreen mode Exit fullscreen mode

Learn more

25. What is Shadow DOM?

Shadow DOM is a set of web standards that allows for encapsulating the structure and styles of elements on a web page. It represents a special segment of the DOM that resides inside an element and is separate from the rest of the page. Shadow DOM is used to create components and widgets with isolated and stylized content that does not conflict with the overall structure of the page.
Learn more

26. What is recursion? How to use it?

Recursion is an approach to problem-solving where a function solves a problem by reusing itself within its own function body. In simple terms, it's when a function calls itself.

A recursive function consists of:

  1. Termination condition or base case
  2. Recursive step - a way to reduce the problem into simpler forms.
function factorial(x) {
   if (x === 0) {
      return 1;
   }
   return x * factorial(x - 1);
}
Enter fullscreen mode Exit fullscreen mode

The base case is a necessary condition; otherwise, it will lead to stack overflow due to an infinite loop of function calls.
Learn more

27. What's the difference between Function Expression and Function Declaration?

Function Declaration is the traditional way of declaring a function.

function foo() {
    console.log('Hello World');
}
Enter fullscreen mode Exit fullscreen mode

Function Expression:

let foo = function() {
    console.log('Hello World');
}
Enter fullscreen mode Exit fullscreen mode

With Function Declaration, the function is created and assigned to a variable, just like any other value. Essentially, it doesn't matter how the function is defined, as it is a value stored in the variable "foo". Function Declarations, however, are processed before the code block is executed, meaning that they are visible throughout the entire code block. On the other hand, Function Expressions are created only when the execution flow reaches them.

Learn more

28. What are constructor functions?

Constructor functions are regular functions that are used to create objects. However, there are two rules for using them:

  1. The name of the constructor function should start with a capital letter.
  2. The constructor function should be called using the new operator.
function User(firstName, lastName) {
    this.firstName = firstName
    this.lastName = lastName
    this.role = 'user'
}

const user = new User('John', 'Johnson')
console.log(user.firstName) // John
Enter fullscreen mode Exit fullscreen mode

When a constructor function is created using the new operator, the following happens:

  1. A new empty object is created and assigned to this.
  2. The code inside the constructor function is executed. Typically, this code will modify the this object and add new properties.
  3. The value of this is returned.

Learn more

29. How can you get a list of keys and a list of values from an object?

You can use Object.keys() to get a list of keys and Object.values() to get a list of values.

const user = {
    firstName: 'John',
    lastName: 'Johnson'
}

const keys = Object.keys(user)
const values = Object.values(user)

console.log(keys) // ['firstName', 'lastName']
console.log(values) // ['John', 'Johnson'] 
Enter fullscreen mode Exit fullscreen mode

Learn more

30. Provide an example of new functionality in ES6.

The most common ones:

  • let and const. Introduction of new keywords let and const for declaring variables with block scope.
  • Arrow functions. The concept of arrow functions allows for more concise and clear function definitions.
function add(a, b) { return a + b } // Regular function
const add = (a, b) => a + b // Arrow function
Enter fullscreen mode Exit fullscreen mode
  • Default parameters. You can define default values for function parameters.
function greet(name = 'Anonymous') { console.log(Hello, ${name}!) }
greet(); // "Hello, Anonymous!"
greet('John') // "Hello, John!"
Enter fullscreen mode Exit fullscreen mode
  • Spread operator (...). The spread operator allows unpacking array or object elements for function arguments or creating new arrays/objects.
const numbers = [1, 2, 3];
console.log(...numbers) // 1 2 3
const array1 = [1, 2, 3]; 
const array2 = [...array1, 4, 5] // [1, 2, 3, 4, 5]
Enter fullscreen mode Exit fullscreen mode
  • Destructuring. Destructuring allows extracting values from arrays or objects and assigning them to variables.
const person = { name: 'John', age: 30, city: 'London' }
const { name, age } = person;
console.log(name, age) // "John 30"
const numbers = [1, 2, 3]
const [first, second] = numbers;
console.log(first, second); // 1 2
Enter fullscreen mode Exit fullscreen mode

Learn more

31. How to do class inheritance in ES6?

Class inheritance is done using the "extends" keyword followed by the name of the parent class.

class User {
    firstName = 'John'
    lastName = 'Johnson'
}

class Customer extends User {
    cart
}
Enter fullscreen mode Exit fullscreen mode

Learn more
And even more

32. What are micro and macro tasks in JavaScript?

In JavaScript, microtasks and macrotasks refer to types of tasks that need to be executed in the event loop. Microtasks are tasks that need to be executed within the current event loop before the browser repaints the page. They are usually added to the execution queue using methods such as Promise.then(), process.nextTick() (in Node.js), or MutationObserver. Examples of microtasks include executing promise handlers and DOM mutations. On the other hand, macrotasks are tasks that need to be executed after the current event loop is finished and before changes are rendered on the screen. This includes tasks added to the event queue using setTimeout, setInterval, requestAnimationFrame, as well as handling input events and network requests. Macrotasks are executed after all microtasks in the current event loop have been processed. The difference between microtasks and macrotasks is important because it determines the order of execution and allows for managing the priority of different tasks in JavaScript. Microtasks have a higher priority and are executed before macrotasks, which allows for faster interface updates and prevents blocking the main JavaScript execution thread.
Learn more

33. What are generators?

Generators produce a sequence of values one by one as needed. Generators work well with objects and make it easy to create data streams.

To declare a generator, a special syntax is used - a generator function.

function* generateSomething() {
    yield 10;
    yield 20;
    yield 30;
    return 40;
}
Enter fullscreen mode Exit fullscreen mode

next() is the main method of a generator. When called, next() starts executing the code until the nearest yield statement. The value may be absent, in which case it is represented as undefined. When a yield is reached, the function execution is paused, and the corresponding value is returned to the outer code.

let generator = generateSomething();
let first = generator.next();
Enter fullscreen mode Exit fullscreen mode

Learn more

34. What are the methods of storing data in a browser?

There are several methods of storing data in a browser:

  • LocalStorage and SessionStorage - store key-value pairs in the browser. The data stored in them is retained after the page is refreshed. Both storage options can only use strings as keys and values, so objects need to be converted using JSON.stringify().
  • Cookie - small strings of data that are stored in the browser. Cookies are usually set by the web server using the Set-Cookie header. The browser will then automatically add them to almost every request to the same domain using the Cookie header. One cookie can hold up to 4kb of data. Depending on the browser, more than 20 cookies per site are allowed.
  • IndexedDB - a built-in database, more powerful than localStorage. It is a key-value store where multiple types of keys are available and values can be almost anything. IndexedDB supports transactions for reliability, supports key range queries and indexes, and allows storing more data than localStorage. IndexedDB is designed for offline applications and can be combined with Service Workers and other technologies.

Learn more
Learn more
Learn more

35. What is the difference between sessionStorage and localStorage?

SessionStorage and localStorage allow storing objects in key-value format in the browser.
The main differences are:

  • localStorage can store up to 10 MB of data, while sessionStorage can store up to 5 MB.
  • Data in localStorage is not deleted, while data in sessionStorage is deleted when the browser tab is closed.
  • Data from localStorage is accessible from any window, while data from sessionStorage is only accessible from the same browser window. Learn more

36. What are regular expressions?

Regular expressions are strings defined by special rules and patterns. They are a powerful tool that allows detecting and working with complex constructions within strings.

let str = "We will, we will rock you"

console.log(str.match(/we/gi)) // ['We', 'we']
Enter fullscreen mode Exit fullscreen mode

Lean more

37. What are WeakSet and WeakMap and how do they differ from Map and Set?

The first difference between WeakMap and Map is that the keys in WeakMap must be objects, not primitive values.
The second difference is in the memory storage of the data structures. The JavaScript engine keeps values in memory as long as they are reachable, meaning they can be used.
Usually, object properties, array elements, or other data structures are considered reachable and are kept in memory as long as the data structure exists, even if there are no other references to them.
In the case of WeakMap and WeakSet, it works differently. Once an object becomes unreachable, it is removed from the data structure.

Learn more

38. Why do two objects with the same fields return false when compared?

Objects are compared based on references to the memory area. For JavaScript, test1 and test2 objects are different, even though they have the same fields. Objects are only equal if they are the same object.

const test1 = { value: 3 }
const test2 = { value: 3 }
console.log(test1 == test2) // false
Enter fullscreen mode Exit fullscreen mode

39. Why can we call methods on primitive types?

JavaScript allows working with primitive data types - strings, numbers, etc. - as if they were objects. Primitive data types have methods.
To make this functionality available, each primitive data type has its own wrapper object: String, Number, Boolean, and Symbol. Thanks to these wrapper objects, primitive data types have different sets of methods, such as toLowerCase() or toUpperCase().

Learn more

40. How to check which class an object was created from?

You can check which class an object was created from using the instanceof operator, taking inheritance into account.

class Person {}
const person = new Person()
console.log(person instanceof Person) // true
Enter fullscreen mode Exit fullscreen mode

Learn more

41. Write code that will log the time spent on the site in seconds every 10 seconds.

let time = 0
setInterval(() => {
    time += 10
    console.log(time)
}, 10000)
Enter fullscreen mode Exit fullscreen mode

Learn more

42. What is a pure function?

A pure function is a function that satisfies two conditions:

  1. Every time the function is called with the same set of arguments, it returns the same result.
  2. It has no side effects, meaning it does not modify variables outside the function.
function calculate(num) {
    return calculate * 0.05;
}
console.log(calculate(15)) 
//calculate() function will always return the same result if we pass the same parameter
Enter fullscreen mode Exit fullscreen mode

43. What is a higher-order function?

A higher-order function is a function that takes another function as an argument or returns a function as a result.

const nums1 = [1, 2, 3]
const nums2 = nums1.map(function(num) {
    return num * 2;
})
console.log(nums2) // [2, 4, 6]
Enter fullscreen mode Exit fullscreen mode

44. Why do we need Promises if we can work with asynchronous code using callbacks?

If we want to asynchronously fetch some data from a server using callback functions, it would result in the following:

func((x) => {
  anotherFunc(x, (y) => {
    andAnotherFunc(i, (j) => {
      // some code
    })
  })
})
Enter fullscreen mode Exit fullscreen mode

This is called callback hell, as each callback is nested inside another, and each inner callback depends on the parent function.

Using Promises, we can rewrite the code above:

func()
.then((x) => {
  return anotherFunc(x)
})
.then((y) => {
  return andAnotherFunc(y)
})
.then((i) => {
  return i
})
Enter fullscreen mode Exit fullscreen mode

With Promises, the execution sequence is clear, making the code more readable.
Learn more

45. Write your own implementation of the bind method.

To implement it, we can use closure and the apply() method to bind the function to the context.

function bind(context, func) {
  return function(...args) {
    func.apply(context, args)
  }
}
Enter fullscreen mode Exit fullscreen mode

46. Write a calculator function with methods plus, minus, multiply, divide, and get. The function must work through optional chaining.

function calculator() {
  let result = 0;

  function plus(val) {
    result += val;
    return this;
  }

  function minus(val) {
    result -= val;
    return this;
  }

  function divide(val) {
    result /= val;
    return this;
  }

  function multiply(val) {
    result *= val;
    return this;
  }

  function get() {
    console.log(result);
    return this;
  }

  return { plus, minus, divide, multiply, get };
}

let calc = calculator();
calc.plus(2).minus(1).plus(19).divide(2).multiply(3).get(); // 30
Enter fullscreen mode Exit fullscreen mode

47. Write a randomSort function that takes an array of numbers and sorts the array in random order.

You can use the sort() method and Math.random() for this.

function randomSort(array) {
  return array.sort(() => {
    return 0.5 - Math.random();
  });
}
const arr = [2, 1, 3, -2, 9]
console.log(randomSort(arr)) // [-2, 2, 1, 3, 9]
console.log(randomSort(arr)) // [2, 1, -2, 9, 3]
console.log(randomSort(arr)) // [-2, 1, 9, 2, 3]
console.log(randomSort(arr)) // [1, -2, 2, 3, 9]
Enter fullscreen mode Exit fullscreen mode

48. Write a deleteGreatestValue function that takes a two-dimensional array of numbers and removes the greatest number from each nested array.

We should iterate through every nested array, get the greatest value of each nested array and delete it.

function deleteGreatestValue(array) {
  for (let i = 0; i < array.length; i++) {
    const max = Math.max(...array[i]);
    const maxIndex = array[i].indexOf(max);
    array[i].splice(maxIndex, 1);
  }
  return array;
}

const arr = [[1, 4, 4], [2, 6, 3], [9, 2, 7]]
console.log(deleteGreatestValue(arr)) // [[1, 4], [2, 3], [2, 7]]
Enter fullscreen mode Exit fullscreen mode

49. Write a sortPeople function that takes an array of strings names and an array of numbers heights, where names[i] == heights[i]. It should sort the names array based on the heights array.

function sortPeople(names, heights) {
  const array = [];
  for (let [i, name] of names.entries()) {
    array.push([name, heights[i]]);
  }
  return array.sort((a, b) => b[1] - a[1]).map(([name]) => name);
}
const names = ['John', 'Maria', 'Alexa', 'Robert']
const heights = [180, 160, 165, 187]
console.log(sortPeople(names, heights)) // ['Robert', 'John', 'Alexa', 'Maria']
Enter fullscreen mode Exit fullscreen mode

50. Write a subsets function that takes an array of numbers nums and returns all possible variations of arrays from those numbers.

function subsets(nums) {
  let result = [[]];

  for (let num of nums) { // Iterate through each number in the nums array
    const currentSize = result.length; // Get the current size of result to use it in the loop.

    for (let i = 0; i < currentSize; i++) {
      let subArray = [...result[i], num]; // Create a new subarray by adding the current number to the result[i] element.
      result.push(subArray);
    }
  }

  return result; // Return all possible variations of arrays from the numbers.
}
Enter fullscreen mode Exit fullscreen mode

51. How to reverse a linked list?

Lets create a function reverseLinkedList that takes a linked list as input and returns the reversed version of that list.

Approach:

  1. It initializes the result variable with null, which will hold the reversed list.
  2. It initializes the root variable with head, which points to the start of the list.
  3. It enters a while loop that continues until root becomes null, indicating the end of the list.
  4. Inside the loop, it checks if result already has elements. If it does, it creates a new list node with the current value root.val and a pointer to the next node result. It then updates result with this new node.
  5. If result doesn't have any elements yet, it creates a new list node with the current value root.val and null as the pointer to the next node. It then updates result with this new node.
  6. After updating result, it moves to the next element in the list by assigning root.next to root.
  7. Once the while loop finishes, it returns the reversed list stored in result.

In summary, the function reverses the linked list by iterating through each node from the head to the tail, creating a new list node for each value and updating the pointers accordingly.

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */

function reverseLinkedList(node) {
  let result = null; // Initialize the result variable with null, it will hold the reversed list.
  let root = head; // Initialize the root variable with head, pointing to the start of the list.

  // While root is not null (until we reach the end of the list)
  while (root) {
    if (result) { // If result already has elements
      result = new ListNode(root.val, result); // Create a new list node with the current value root.val and a pointer to the next node result. Update result.
    } else { // If result doesn't have any elements yet...
      result = new ListNode(root.val, null); // Create a new list node with the current value root.val and null as the pointer to the next node. Update result.
    }
    root = root.next; // Move to the next element in the list.
  }
  return result; // Return the reversed list.
}
Enter fullscreen mode Exit fullscreen mode

52. How to sort a linked list?

Lets create a function sortList that takes a linked list as input and returns the sorted version of that list.

Approach:

  1. Check if the given linked list is empty or not.
  2. Traverse the linked list and store the node values into an array.
  3. Sort the array using the built-in sort() method.
  4. Create a new linked list using the sorted array.
  5. Return the head of the created linked list.
/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
function sortList (head) {
  if (!head) {
    return null;
  }
  let root = head;
  let arr = [];

  while(root){
    arr.push(root.val);
    root = root.next;
  }
  arr.sort((a, b) => a - b);

  let node = new ListNode(arr[0]);
  head = node;

  let temp = head;

  for(let i = 1; i < arr.length; i++){
    let node = new ListNode(arr[i]);
    temp.next = node;
    temp = temp.next;       
  }
  return head;
};
Enter fullscreen mode Exit fullscreen mode

Conclusion

Preparing for these questions, studying the topics covered, and reviewing relevant resources can improve your chances of successfully passing the interview. This post is part of a series of posts on interview questions.

I look forward to your reactions and comments.
Good luck in your interview!

💖 💪 🙅 🚩
m_midas
Yan Levin

Posted on August 12, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related