Interview Questions for Web Developer - JavaScript
Tags: javascript, interview
Published: 2024-01-01 10:29:09

## Navigation

- [JavaScript Basics](#javascript-basics)
- [Variables & Data types](#variables-amp-data-types)
- [Functions & Loops](#functions-amp-loops)
- [Objects & Arrays](#objects-amp-arrays)
- [Prototypes, inheritance and this](#prototypes-inheritance-and-raw-this-endraw-)
- [Sources / Literature](#sources-literature)
 

---

## JavaScript Basics

**1. What is the javascript?** - [_Answer_](https://developer.mozilla.org/en-US/docs/Web/JavaScript)

**2. What is the Scope?** - [_Answer_](https://developer.mozilla.org/en-US/docs/Glossary/Scope)

**3. What is an Event Loop? How does it work?** - [_Answer_](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Event_loop)

---

## Variables & Data types

**1. What declaring variables does JavaScript have? What is the difference between them?**

- `var`: var was the original way to declare variables in JavaScript before ES6. Variables declared with var have function scope or global scope if declared outside a function. They can be redeclared and updated.

- `let`: Introduced in ES6, let allows block-scoped variables. Variables declared with let are limited to the block (enclosed by curly braces) in which they are defined. They cannot be redeclared in the same scope but can be updated.

- `const`: Also introduced in ES6, const is used to declare constants whose values cannot be re-assigned or re-declared. const variables are block-scoped and must be initialized at the time of declaration.

**2. What are the various data types that exist in JavaScript?** - 
There are eight data types that are present in JavaScript:
- String
- Number
- Boolean
- Object
- Null
- Undefined
- BigInt
- Symbol

**3. What is the difference between `null` and `undefined` ?**
The `undefined` usually occurs as a default value in JavaScript, representing the absence of an assigned value, while `null` is explicitly set by the programmer to indicate a deliberate absence of a value. Both `null` and `undefined` are distinct types in JavaScript, but they are often used interchangeably to signify absence or lack of a meaningful value.

**4. How to check the type of some operand? What types have the following operands: `null`, `undefined`, `[]` and `NaN`?**

For type checking a type, use `typeof` operator that returns a string indicating the type of the operand's value.

```javascript
console.log(typeof null) // object
console.log(typeof undefined) // undefined
console.log(typeof NaN) // number
console.log(typeof []) // object
```

**5. What limitations have numbers in JavaScript and how to overcome them?**

JavaScript as most programming languages has problems with math and huge/small numbers, which all come from the hardware itself. As a result, we get some strange behavior in our codebase e.g.

```javascript
console.log(0.1 + 0.2); // Output: 0.30000000000000004 (rounded due to precision)
```

```javascript
console.log(9007199254740992); // Output: 9007199254740992 (accurate)
console.log(9007199254740993); // Output: 9007199254740992 (loss of precision)
```

_Precision and Representation:_

- JavaScript numbers are stored as 64-bit floating-point numbers, limiting their range. Numbers outside the range of ±(2^53 - 1) may not be represented accurately.

- JavaScript uses the IEEE 754 standard for representing numbers, which can lead to precision issues with floating-point arithmetic. This can cause unexpected behavior when performing calculations involving decimals due to limited precision.

In practice when we work with huge/small and decimal numbers, we are required to mind `Number.MAX_SAFE_INTEGER` and `Number.MIN_SAFE_INTEGER` edges. if the number exceeds them use BigInt instead of regular numbers. For decimals, we can be used in-build Math functions to get the required results.

```javascript
const bigIntNum = 123456789012345678901234567890n; // Using the "n" suffix
const anotherBigInt = BigInt("9007199254740993"); // Creating from a string using BigInt()

/// 

const result = 0.1 + 0.2;
const fixedResult = (result).toFixed(1); // Round to one decimal place

console.log(parseFloat(fixedResult)); // Output: 0.3
```

---

## Functions & Loops

**1. Name ways of declaring functions and their differences in JavaScript?**

- **_Function declaration_**
The function declaration uses the keyword _function_ to declare a function, this method allows to use function before it is defined e.g.

```javascript
doSomething()

function doSomething () {
  //...some actions
}
 ```

- **_Function Expression_**
The assigning a function to some variable, in this case, if the function is called before the declaration causes the _ReferenceError_
```javascript
doSomething() //output: ReferenceError

const doSomething = function () {
  console.log("Function Expression worked")
}

doSomething() // output: "Function Expression worked"
 ```

**2. What are arrow functions, How are they different from regular functions and where should use them?**
The arrow functions are a concise way to write functions in JavaScript introduced in ES6 (ECMAScript 2015) with a more compact syntax compared to regular functions. They differ from regular functions in a few ways:
- use `=>` to define a function;
- do not have its own `this` context; they inherit `this` from the surrounding code;
- do not have the `arguments` object;

Can be used as callbacks inside promises, as short anonymous functions inside array methods, where you want to preserve the lexical scope of `this`

Examples:

```javascript
//With many arguments:
const doSomething = (a, b) => {return a + b};

//With instant return:
const doSomething = (a, b) => a + b;

//With one argument:
const doSomething = a => a + 1;

//Inside array:
const sum = [1, 2, 3].reduce((acc, cur) => acc + cur, 0);

//Inside promise
fetch('https://some-api').then(res => res.json());
```

**3. What IIFE stands for and where should be used?**
IIFE stands for "Immediately Invoked Function Expression."

An IIFE is a JavaScript design pattern that involves defining and immediately executing a function. It is constructed by enclosing the function within parentheses ( ) to create a function expression and then adding an additional set of parentheses ( ) immediately after to invoke the function e.g.

```javascript
(function() {
    // Function body
})();

(() => {
   // Function body
})()
```
**_Use cases for IIFE:_**
- **Encapsulation**: IIFEs are commonly used to create a new scope, preventing variable declarations from polluting the global scope. This helps avoid naming conflicts and keeps variables private.

- **Initialization**: They are useful for initializing code that should run once when the script loads, setting up configurations, or executing setup tasks.

- **Module Patterns**: IIFEs are a building block for various module patterns in JavaScript, like the revealing module pattern or module encapsulation, allowing the creation of private variables and functions while exposing only necessary functionalities.

**4. What is _closure_ in JavaScript and how it works?** 
In JavaScript, a closure is a combination of a function and the lexical environment within which that function was declared. Closures allow functions to access and utilize variables from their outer scope even after the outer scope has finished executing.

Here's how closures work:

1. Lexical Scoping: JavaScript uses lexical scoping, which means that functions can access variables defined in their outer scope at the time they were created, regardless of where they are called from.

2. Function within a Function: When a function is defined inside another function, the inner function has access to the outer function's variables and parameters, forming a closure.

3. Preservation of the Outer Scope: Closures "remember" the variables from their outer scope even after the outer function has finished executing. This allows the inner function to maintain access to those variables.

```javascript
const mainFunction = () => {
  const arr = [];

  return (value) => {
   arr.push(value);
   console.log(arr)
 }
}

const returnedFunction = mainFunction();

returnedFunction("1") // will console ["1"];
returnedFunction("2") // will console ["1", "2"]
```

**5. What is the anonymous function?**
An anonymous function in JavaScript is a function that does not have a name assigned to it. Instead of being declared with a specific identifier (name), it is created inline without a name reference. These functions are often used as callbacks or function expressions where the function itself doesn't need to be named or referenced elsewhere in the code.

```javascript
const myFunction = function() {
  console.log('This is an anonymous function');
};

// Using an anonymous function as a callback
setTimeout(function() {
  console.log('This function will execute after 1 second');
}, 1000);
```

---

## Objects & Arrays

**1. Is the one `{}` equal another `{}`? How to compare two objects?** 

In JavaScript, when comparing two objects using the equality operators (`==` or `===`), these operators check for equality by comparing the references to the objects, not their contents.

```javascript
const objA = { a: 1, b: 2, c: 3 };
const objB = { a: 1, b: 2, c: 3 };

console.log(objA === objB); // false
```

Actually, there are several ways to compare objects in JavaScript. The first that may come to mind is to iterate through keys and values and compare them that will look something like: 

```javascript
function isEqual(obj1, obj2) {
  const keys1 = Object.keys(obj1);
  const keys2 = Object.keys(obj2);

  if (keys1.length !== keys2.length) {
    return false;
  }

  for (const key of keys1) {
    if (obj1[key] !== obj2[key]) {
      return false;
    }
  }

  return true;
}

const objA = { a: 1, b: 2, c: 3 };
const objB = { a: 1, b: 2, c: 3 };
console.log(isEqual(objA, objB)); // true
```

Also we can transform objects to JSON strings and compare them like:

```javascript

const objA = { a: 1, b: 2, c: 3 };
const objB = { a: 1, b: 2, c: 3 };

const stringA = JSON.stringify(objA);
const stringB = JSON.stringify(objB);

console.log(stringA === stringB); // true
```

Or to use some third-party libs like `isEqual` from lodash.
 
**2. How to copy an Object in JavaScript?**
There are a several ways to copy an Object in JavaScript:

`Object.assign()`: Creates a shallow copy of an object. Copies enumerable own properties from one or more source objects to a target object. Modifies the target object and returns it. Non-enumerable properties and properties on the prototype chain are not copied.
```javascript
const originalObject = { a: 1, b: 2 };
const copiedObject = Object.assign({}, originalObject);
```

`Spread syntax (...)`: Creates a shallow copy of an object. Copies enumerable own properties from the source object(s) to the new object. Can be used to merge objects or create new objects with copied properties. Similar to `Object.assign()`, it doesn't deeply clone nested objects or handle non-enumerable properties.
```javascript
const originalObject = { a: 1, b: 2 };
const copiedObject = { ...originalObject };
```

`JSON.stringify() and JSON.parse()`: Creates a deep copy of an object but works only with JSON-safe data. Converts the object to a JSON string and then parses it back into a new object. Loses reference to functions, non-JSON-safe objects (like Date objects), and non-enumerable properties.
```javascript
const originalObject = { a: 1, b: 2 };
const copiedObject = JSON.parse(JSON.stringify(originalObject));
```

`Object.create()`: Creates a new object with the specified prototype object and properties. Allows for setting the prototype of the new object explicitly. Can copy properties from another object, but doesn't create a direct copy of the source object's properties.
```javascript
const originalObject = { a: 1, b: 2 };
const copiedObject = Object.create(Object.getPrototypeOf(originalObject), Object.getOwnPropertyDescriptors(originalObject));
```

**3. How to check that an object has property?**
Using the `in` operator, however, it also returns true if the object's prototype has this property. The second approach uses `hasOwnProperty()` method on an object.

```javascript
const proto_obj = {
	name: 'user'
};

const obj = {
  color: 'red'
}

obj.__proto__ = proto_obj;

console.log('color' in obj); // true
console.log('name' in obj); // true
console.log(obj.hasOwnProperty("color")) // true
console.log(obj.hasOwnProperty("name")) // false
```

## Prototypes, inheritance and `this`

**1. What is a prototype in JavaScript? How to work with it?**
In JavaScript, everything is basically primitive or an object. Objects on the other hand have a prototype. The prototype is a reference to another object that the current object inherits properties and methods from. It forms the basis for JavaScript's prototypal inheritance.

**2. How to check that an object has property?**
Using the `in` operator, however, it also returns true if the object's prototype has this property. The second approach uses `hasOwnProperty()` method on an object.

```javascript
const proto_obj = {
	name: 'user'
};

const obj = {
  color: 'red'
}

obj.__proto__ = proto_obj;

console.log('color' in obj); // true
console.log('name' in obj); // true
console.log(obj.hasOwnProperty("color")) // true
console.log(obj.hasOwnProperty("name")) // false
```

**3. Explain the `this` keyword, and how it works?**

In JavaScript, the `this` keyword is a special identifier that refers to the current instance of an object or the context in which a function is invoked. The value of this is determined by how a function is called or how an object is accessed.

Here are some examples of usages _this_:

- When used inside a function, this depends on how the function is called. If the function is a regular function (not a method of an object or part of a class), `this` refers to the global object (or undefined in strict mode).

```javascript
function myFunction() {
  console.log(this);
}

myFunction(); // global object | window
```

- When used inside a method (a function that is a property of an object), `this` refers to the object on which the method is called.

```javascript
const myObject = {
  myMethod: function() {
    console.log(this);
  }
};

myObject.myMethod(); // Points to myObject
```

- When used inside a constructor function (a function called with the new keyword to create an instance), `this` refers to the newly created instance.

```javascript
function MyClass() {
  this.myProperty = 42;
}

const myInstance = new MyClass();
console.log(myInstance.myProperty); // 42
```

- In event handlers, `this` often refers to the DOM element that triggered the event.

```javascript
document.getElementById('myButton').addEventListener('click', function() {
  console.log(this); // Points to the clicked button element
});
```

**4. What is `call()`, `apply()` and `bing()`?**
The `call()`, `apply()`, and `bind()` methods are used to explicitly set the value of `this` for a function. They allow you to control the context in which a function is executed. These methods are often used in situations where the default behavior of `this` is not sufficient, such as when you want to invoke a function with a specific object as its context.

Usage examples:

- [call()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call)

```javascript
const obj1 = { name: 'Object 1' };

function sayHello(greeting) {
  console.log(`${greeting}, ${this.name}`);
}

sayHello.call(obj1, 'Hello'); // Outputs: Hello, Object 1
```

- [apply()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply)

```javascript
const obj2 = { name: 'Object 2' };

function sayHi(greeting) {
  console.log(`${greeting}, ${this.name}`);
}

sayHi.apply(obj2, ['Hi']); // Outputs: Hi, Object 2
```

- [bind()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind)

```javascript
const obj3 = { name: 'Object 3' };

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

const boundFunction = greet.bind(obj3, 'Greetings');
boundFunction(); // Outputs: Greetings, Object 3
```

## Other (For now)

**1. What is the difference between `==` and `===`?**
In JavaScript, == (equality operator) and === (strict equality operator) are used for comparison, but they differ in how they evaluate values:

```javascript
console.log(1 == '1') // true
console.log(1 === '1') // false
```

**2. What is the difference between LocalStorage, SessionStorage та cookies?**

- **_LocalStorage_** is a web storage API in web browsers that allows for persistent storage of key-value pairs in the browser with no expiration date, remaining stored even after the browser is closed.

- **_SessionStorage_** is another web storage API that stores data in the browser for the duration of the page session, clearing the data when the session ends or the browser is closed.

- **_Cookies_** are small pieces of data sent from a website and stored in the user's browser, capable of holding limited information and having expiration dates, often used for tracking, authentication, and personalization purposes.

**3. What is the difference between for..of and for...in ?**

- for...of is used for iterating over values of iterable objects like arrays and strings.

- for...in is used for iterating over keys or property names of objects, including inherited properties in the prototype chain.


**4. What is Map & Set? When it should be used?**

- **_Map_**: A Map is a collection of key-value pairs where each key can be of any data type, including objects or primitive values. It maintains the insertion order of its elements, and keys can be iterated in the order of their insertion. It allows storing unique keys and offers various methods to interact with the data, such as `set()`, `get()`, `delete()`, `has()`, etc. Use Map when you need to associate keys with values, especially when the keys are not simple strings or when you want to maintain the insertion order of key-value pairs. It's useful for scenarios where a unique identifier (key) is associated with some data (value).

- **_Set_**: A Set is a collection of unique values, where each value must be unique within the set. It does not allow duplicate elements, and it also maintains the insertion order of elements. It provides methods like `add()`, `delete()`, `has()`, etc., to manage and interact with the set. Use Set when you need to maintain a collection of unique values and you want to ensure that each element appears only once within the collection. It's useful for removing duplicates from arrays, managing unique values, or checking for the existence of elements efficiently without needing to manage uniqueness manually.

**5. How is asynchronous code executed in JavaScript?**
In JavaScript, asynchronous code is executed using an event-driven, non-blocking model. When an asynchronous operation is initiated (such as fetching data from a server or setting a timer), it gets queued in the event loop, allowing the main execution thread to continue processing other tasks. Once the asynchronous operation is completed or ready, its associated callback function or promise is placed in the callback queue. The event loop continuously checks for completed tasks in the callback queue and executes their corresponding callback functions, allowing the program to handle asynchronous tasks without blocking the main thread, ensuring responsiveness in applications.


**6. What are the three phases of event propagation?**
Capturing > Target > Bubbling. During the capturing phase, the event goes through the ancestor elements down to the target element. It then reaches the target element, and bubbling begins.
![event_propagation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/blkcaqeal2ozjw6e33z8.png)

---

## Sources / Literature

- [The Modern JavaScript Tutorial](https://javascript.info/)

- [MDN JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript)