Monday, January 28, 2019

JavaScript Interview Questions


Here is a list of beginner level JavaScript interview questions.
1. What are the various ways of declaring a variable available in JS?
Answer:
Since the good old days, JS has had the var keyword for declaring new variables.
var name = "Emma Watson";
However, due to the limitations and nuances of that, ES6 introduced two new keywords for declaring new variables let & const:
let name = "Emma Watson";

const name = "Emma Watson";
const : Declares an immutable variable whose value cannot be changed during the entire course of execution of the program. Doing so throws a TypeError.
let : Declares a mutable variable within the nearest enclosing block.
var : Declares a mutable variable within the nearest function block.
Declaring global variable as var pollutes the global namespace and can result in bizarre errors in large codebases. let prevents that as it is only visible in the nearest block scope. Also, if declared globally, it is not attached to the window object.
var notAwesome = 1;

console.log(window.notAwesome); // 1

let awesome = 1;

console.log(window.awesome); // undefined
2. How can you declare an array in JavaScript?
Answer:
We can declare an array in JavaScript using the square bracket syntax.
const numbers = [1, 2, 3, 4, 5];
We can also use the Array constructor, supplying it the number of elements we want our array to contain. However, note that this initializes the array with undefined. To get rid of that, you can use the fill method to populate the array with real values.
let numbers = new Array(10);

console.log(numbers); // [undefined x 10];

numbers = new Array(10).fill(0);

console.log(numbers); // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
3. What are JavaScript Objects?
Answer:
JavaScript objects are containers that house name,value pairs inside them. They can be used to accumulate information about an entity in one place.
For example, if you need to store information about a user in JavaScript, a brute-force way is to use multiple variables and store the information in them.
const name = "Abhishek Soni";
const phone = "00000000000";
const email = "email@email.com";
However, maintaining those variables for 10 or 100 users will become a bottleneck. We can store that information in one variable (container of information) using JS objects:
const user = {
  name: "Abhishek Soni",
  phone: "00000000000",
  email: "email@email.com"
};
4. Does JavaScript have a Boolean data type?
Answer:
Yes. JavaScript has a special data type to represent boolean variables. The two special values are true and false. They can be assigned to any JS variable to make it boolean:
let isFlagged = true;
let isNotFlagged = false;
5. What are the various types of flow control/looping statements available in JS?
Answer:
JavaScript supports three types of looping statements:
1.    If-Else
2.    For
3.    While
4.    Do-While
If-Else
if (name === "Abhishek Soni") {
  return "Admin";
} else {
  return "Employee";
}
For
We can use the for loop to perform an operation to a list of values or execute a block of code multiple times.
for ( let i = 0; i < 10; i++) {
    // Executing block
    console.log(i);
}

The above program loops over the executing block, until a pre-defined condition is true.(Here: `i < 10`)

Each iteration increments the value of `i` (`i++`). Once the condition is reached, the loop ends.
While
let i = 0;

while (i < 10) {
  i++;
  console.log(i);
}
Another way of achieving what the for loop did in the above code snippet is to use the while loop. While loop is similar to for loop in the sense that it continues the execution of its execution block until a pre-defined condition fails.
Do-While
let i = 1;
do {
  i++;
  console.log(i);
} while (i < 10);
do-while loop works just like while except it executes at least once. (Just like any other programming language.)
6. Write a program to reverse a string in JS.
Answer:
Steps involved in revering a string in JS are: (1) split the string into its consituent characters (Array), (2) call the reverse method to reverse the order of characters in the string and (3) join the characters back. This is illustrated below.
function reverse(string) {
  return string
    .split("")
    .reverse()
    .join("");
}
Here is list of intermediate level JavaScript interview questions.
1. What is the difference between == and === check in JS?
Answer:
== : Simple equality check with type conversion supported
console.log(1 == "1"); // true
=== : Strict equality check with no type conversion
console.log(1 === "1"); // false
2. Is this the correct way of copying an object in JS?
Answer:
const object1 = { a: 1, b: 2 };
const object2 = object1;
No. object2 is merely a reference to the same object. Changing a property using object2 will also result in the same property getting changed for object1 . This happens because object2 simply points to the object created by object1 . It doesn’t hold it’s own copy of the object. This is illusrated below:
object2.a = 2;
console.log(object2.a); // 2
console.log(object1.a); // 2
The correct way of cloning an object (introduced in ES6) is by using the Object.assignmethod:
const object1 = { a: 1, b: 2 };
const object2 = Object.assign({}, object1);
3. What will be the output of the following code?
Answer:
console.log(1);

console.log(2);

setTimeout(() => {
  console.log(3);
}, 0);

console.log(4);
The output, surprisingly, will be
1;
2;
4;
3;
This happens because JS treats callback functions (like the one sent to setTimeout) differently. You can think of them as second-class citizens in JavaScript wherein they are always called (executed) after the first-class citizens (other functions) are finished. This is the reason why a 0 ms delay- timeout function doesn’t execute its callback immediately. It has to wait for all the other functions to return first.
4. Will the following program crash? Explain your answer.
function sum(a, b) {
  return a + b;
}

sum.functionName = "Add";
Answer:
The program will not crash. Attaching a property to a function is perfectly legal in JS. In fact, that property can be read back later, if need be. This is possible because functions in JS are just a special type of Objects and hence, properties can be attached to them.
console.log(sum.functionName); // Add
5. What are callback functions?
Answer:
A callback function is a function passed to another function, where it is executed after some pre-defined processing has been completed. In node.js callbacks are used to return results of asynchronous methods such as I/O operations, etc.
function readFile(name, callback) {
  let file;

  // READ FILE HERE ASYNCHRONOUSLY

  setTimeout(() => {
    callback(file);
  }, 2000);

  /**
   * return file; (Using this will immediately return undefined as
   * the file variable does not contain anything yet.)
   */
}
6. What is the spread operator in JS?
Answer:
The spread operator, or the three dots, (…) is a new operator introduced in ES6. It allows the expansion of an iterable (e.g., Array) into its constituent elements.
const t = [1, 2, 3];

const s = [...t, 4, 5, 6];

console.log(s); // [1, 2, 3, 4, 5, 6];
7. Given an array with duplicates, what is the easiest way to remove the duplicates from it?
const numbers = [1, 2, 3, 4, 5, 5, 5, 5, 5, 5];
Answer:
Here’s a one-liner to remove duplicates from an array. (ES6, of course!)
function removeDuplicates(array) {
  return [...new Set(array)];
}
Set was introduced in ES6 and is similar to the Sets we encounter in Mathematics: They can’t have duplicates. After we have done that, we simply convert the Set back to an array by using the spread operator.
8. What does the following code do?
const person = {
  name: "Abhishek Soni",
  age: 23,
  place: "Edmonton",
  phone: 0000000000
};

delete person.phone;
Answer:
We are first declaring an object and then removing a key named phone from the object. (Note that deleting a key like this is not recommended as the call would still succeed even if the phone key didn’t exist on the person object. To make sure you are deleting the right key, you might want to iterate over the key and only delete if the target key is found.)
for (let key in person) {
  if (key === "phone") {
    delete person[key];
  }
}
9. How do you cancel invocation of a method set to be executed every 10ms using setInterval?
Answer:
We can think of setInterval as an alarm that keeps firing after a pre-defined interval has passed. When setting this alarm, setInterval returns an id of the alarm. This ID can be later used to cancel the alarm, if need be, using the cancelInterval method:
const loggerID = setInterval(() => {
  console.log(logs);
}, 10);

// Somewhere down the road

clearInterval(loggerID);
10. What is the difference between forEach and filter?
Answer:
forEachfilter, and map are all iterator methods that are attached to Arrays in JavaScript. They can be called from any Array with a callback function. The callback function receives the array elements (and the indexes) depending on the function being called.
forEach: Iterates over the entire array, invoking the callback function on each element present in the array. Doesn't return anything.
const numbers = [1, 2, 3];

numbers.forEach(num => {
  console.log(num * 2);
});

// Logs 2, 4, 6;
map: Iterates over the entire array, invoking the callback function on each element. The return value of the callback function is pushed to a new result array. Returns a new result array.
const numbers = [1, 2, 3];

const twiceNumbers = numbers.map(num => num * 2);

console.log(twiceNumbers); // [2, 4, 6];
filter: Iterates over the entire array, invoking the callback function on each element. If the callback function returns true for a particular element, that element is "filtered" out. Returns a new array.
const numbers = [1, 2, 3];

const evenNumbers = numbers.filter(num => num % 2 === 0); // true only for even numbers

console.log(evenNumbers); // [2]
reduce:
Advanced JavaScript Interview Questions
Here is a list of Advanced level JavaScript interview questions.
1. What is a Promise? Make the following function return a Promise.
function delay() {
  setTimeout(() => {
    return 10;
  }, 2000);
}
Answer:
Promise is an object that may either return a value sometime in the future. When you return a Promise, its status is pending and it hasn’t yet returned any value. This return value of a Promise depends on whether the Promise is resolved or rejected. If the Promise is resolved, the value will be returned. If the Promise is rejected, it returns an Error object explaining why the call was rejected.
fetch("URL")
  .then(data => {
    console.log(data); // sometime in the future
  })
  .catch(err => () => {
    // handle error
  });
Promises help us in preventing callback hell and also make the code more readable. Because of the asynchronous nature of callback functions, Promises make them look linear for better understanding. Here’s a promisified version of the above delay function:
function delay() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(10);
    }, 2000);
  });
}
2. How is the async/await paradigm different from Promises?
Answer:
The async/await paradigm involves two separate keywords that change the meaning of the expression they are used with. First, let us talk about async:
async function makeRequest() {
  // complicated fetch code here
}
Attaching the async keyword in front of a function makes it always return a Promise. This can be used to make a normal asynchronous function to return a Promise. But the real power of async/await paradigm can be harnessed by using await.
const data = await makeRequest();
The await keyword makes the function wait for the Promise to be resolved and then return its results to the data variable. Otherwise, we would have had to attach a .thento the call, similar to how we do in case of Promises. await just makes our life easier and does the waiting for us itself. This makes our code more linear and easier to read and understand. (It still is asynchronous, of course!).
3. What is closure? What is the most prominent application of closure in JS?
Answer:
Closure is simply an inner function accessing (and using) the variables out of its scope, usually declared in an outer function or block. This is illustrated below:
const greet = name => {
  return {
    sincerely: () => {
      return `Hello, ${name}!`;
    },
    withAnger: () => {
      return `${name}`;
    }
  };
};

greet("Abhishek").sincerely(); // Hello, Abhishek!
Here, the two functions, sincerely and withAnger have access to the name variable, even though it was declared out of their scope. Also, note that the original greetmethod has long returned when the sincerely method is invoked. Despite that, the name variabe is still accessible as if it was magically *enclosed *by the inner function. That, my friend, is Closure.
4. How does the map method work in JS? Implement map from scratch.
Answer:
The map method attached to Arrays in JS is used to apply a transformation function to every element of the array and return the results.
const integers = [1, 2, 3];

const integersDoubled = integers.map(i => i * 2);

console.log(integersDoubled); // [2, 4, 6];
The map method can be implemented as follows:
const myMap = (array, callback) => {
  const result = [];

  for (let i = 0; i < array.length; i++) {
    result.push(callback(array[i]));
  }

  return result;
};
5. How can you prevent your global variables from polluting the global namespace?
Answer:
Immediately Invoked Function Expressions, also known as IIFEs are a class of functions that are, as the name suggests, immediately invoked (or called) as soon as they are declared. The most common use case of IIFEs is to block-scope variables and to hide functionality from the outside world.
(function() {
  const age = 27;
})();

age; // ReferenceError
We can use this to hide our script’s global variables from polluting the global namespace without compromising on functionality.
6. What are short-circuiting expressions? How are they useful in JS?
Answer:
Short-circuiting expressions, not a JS thing per se, are expressions in which the second argument is only evaluated if required. They are used with boolean operators, specifically AND (&&) and OR (||)This is illustrated below:
firstArgument && secondArgument;
firstArgument || secondArgument;
In the first expression, if firstArgument evaluates to false, then secondArgument is not evaluated at all.
This can be used when we are trying to access property names from dynamically-returned data, for example, by a fetch request.
const data = { name: { second: "Watson" } };

console.log(data.phone.area); // TypeError
To prevent the above error, what we can do is use short-circuiting expressions:
const data = { name: { second: "Watson" } };

console.log(data.phone && data.phone.area); // will either result in the value or return undefined but there will be no Error.
In the second expression using ||, if firstArgument evaluates to false, secondArgumentis evaluated. If firstArgument evaluates to true, then the secondArgument is not evaluated at all. This can be used to assign default values to variables.
const data = { name: "Emma Watson" };
const name = data.name || "Unknown";
7. Implement a Singly LinkedList in JavaScript.
Answer:
Every LinkedList has a head, which corresponds to the first node in the list, and a pointer (strategically called next) that points to the next element in the list. This simple and powerful data structure can be implemented in JS as follows. First, we represent a single Node in the list:
class Node {
  constructor(item, next = null) {
    this.data = item;
    this.next = next;
  }
}
The node has a data attribute and a next attribute. The data attribute tells us what this node contains, and the next attribute tells us where the next element in the list is.
And now that we have a node set up, we can link it together to form our LinkedList:
class LinkedList {
  constructor() {
    this.head = null;
  }
}
A new LinkedList can be initialized as follows:
const list = new LinkedList(); // empty list
To insert a node into this list, we can attach a node to the head of the list:
list.head = new Node(2); // List = 2-> null
Adding a new element is easy:
list.head.next = new Node(5); // List = 2-> 5 -> null
This can be wrapped up in a function and is left as an exercise for the reader.
8. What is hoisting in JavaScript?
Answer:
Hoisting in JS refers to the fact that the variable declerations are hoisted to the top of the scope in which they are declared.
function greet() {
  console.log(name);
  var name = "Abhishek Soni";
}

greet(); // Undefined
Technically, since the variable has not been declared when the console.log method is called, it should throw a ReferenceError. However, because of hoisting, message's declartion is hoisted to the top of the function block: (As if it was first declared.)
function greet() {
  var name;
  console.log(name);
  var name = "Abhishek Soni";
}
9. What is the this keyword in JS?
Answer:
this is a special keyword that refers to the object from where it is called. For example,
function sum() {
  console.log(this); // Logs the Window object
}

sum();
This happens because sum is declared in the global scope and is thus, attached to the window object. When we call the sum function, what we are actually calling is this:
window.sum();
What is on the left hand side of the dot is what this gets assigned to.
In case of calling a method defined inside a class, this refers to the class itself. This is similar to objects.
const user = {
  name: "Emma",
  greet: function() {
    console.log(this.name);
  }
};

user.greet();
Classes:
class User {
  constructor(name) {
    this.name = name;
  }

  greet() {
    console.log(this.name);
  }
}

const user = new User("Abhishek");
user.greet();
10. What is Prototypal inheritance in JS? How is it different from class based inheritance?
Answer:
With a few exceptions, almost all the data types in JS inherit from one Parent type called Object. Before ES6, JS did not have an implicit inheritance model. To represent real-world objects in code, and then extend it, JS allowed prototypal inheritance. To illustrate that, let us imagine we need to represent Vehicles in JS. Since most of the Vehicles will have some common features, we can create a parent class and multiple child classes can inherit from the parent class.
Pre ES6:
In case of Prototypal inheritance, we can attach methods to a generic object and treat it as the Parent.
function Vehicle(name) {
  this.name = name;
  this.speed = 0;
}

Vehicle.prototype.accelerate = function(speed) {
  this.speed += speed;
};

Vehicle.prototype.decelerate = function(speed) {
  this.speed -= speed;
};

/**
 * Now let us create a car that extends Vehicle.
 */
function Car(name, color) {
  this.name = name;
  this.color = color;
}

// Make Vehicle its prototype

Car.prototype = Object.create(new Vehicle());

let ferrari = new Car("ferrari", "red");
Car's prototype is now Vehicle. And Vehicle's prototype is Object.
When we call the accelerate method on an instance of Car, JS first looks for implementation of the method in Car. If it is not found, it goes up the prototypal chain and checks if it is attached to Vehicle. Since it finds the method, it executes it in the context of Car. This way, we can reuse functionality by only defining it once and mimic the Object-Oriented Paradigm in JavaScript.
Car -> Vehicle -> Object -> null
Post ES6:
class Vehicle {
  constructor(name) {
    this.name = name;
    this.speed = 0;
  }

  accelerate = speed => {
    this.speed += speed;
  };

  decelerate = speed => {
    this.speed -= speed;
  };
}
Now that we have our Parent class set up, we can extend it to create a variety of vehicles with the common methods residing in the Parent Class.
class Car extends Vehicle {
  constructor(name, color) {
    super(name);
    this.color = color;
  }
}
Look how subtely we added a new property named color while reusing the logic we had for Vehicle.
Tips to nail the JavaScript interview
Below are a few important tips to perform well in your interview.
1.    Be a problem-solver: Do not panic if you don’t know the answer. Often, the interviewer is interested in your problem-solving abilities rather than how fast you get to the answer.
2.    Your thoughts matter: When going through a piece of code, always remember that it is extremely important to voice your thoughts so that the interviewer knows how you plan to solve the problem. Think out loud and do not be afraid of being wrong.
3.    Do not cover up: If you have not heard of a concept that the interviewer is asking, accept it and move on. It’s better to accept your mistakes than to cover them up.
4.    Keep calm: Lastly, do not forget to be calm and composed rather than act all scared. It is just JavaScript. Some objects here and there, with functions on the side, and sprinkled bundlers: Boom!


No comments:

Post a Comment

Which Python course is best for beginners?

Level Up Your Python Prowess: Newbie Ninjas: Don't fret, little grasshoppers! Courses like "Learn Python 3" on Codecade...