๐Ÿ“œ JavaScript Interview Guide

Data Types & Variables

What are the different data types in JavaScript?

JavaScript has 8 data types: 7 primitive types and 1 non-primitive type.

Primitive Types:

Non-Primitive Type:

// Examples
let num = 42;                    // Number
let str = "Hello";               // String
let bool = true;                 // Boolean
let undef;                       // Undefined
let empty = null;                // Null
let sym = Symbol('id');          // Symbol
let big = 123456789012345678901234567890n; // BigInt
let obj = { name: "John" };      // Object

Functions & Scope

What are the different ways to create functions in JavaScript?

1. Function Declaration:

function greet(name) {
    return `Hello, ${name}!`;
}

2. Function Expression:

const greet = function(name) {
    return `Hello, ${name}!`;
};

3. Arrow Function (ES6):

const greet = (name) => `Hello, ${name}!`;

4. IIFE (Immediately Invoked Function Expression):

(function() {
    console.log("This runs immediately!");
})();

Scope in JavaScript:

Hoisting

What is hoisting in JavaScript?

Hoisting is JavaScript's behavior of moving variable and function declarations to the top of their scope during compilation.

Variable Hoisting:

console.log(x); // undefined (not error)
var x = 5;

// This is how JavaScript interprets it:
var x;
console.log(x); // undefined
x = 5;

Function Hoisting:

sayHello(); // "Hello!" - works fine

function sayHello() {
    console.log("Hello!");
}

let and const:

console.log(y); // ReferenceError
let y = 10;

console.log(z); // ReferenceError
const z = 20;

Key Point: let and const are hoisted but in a "temporal dead zone" until declaration.

Closures

What are closures in JavaScript?

A closure is a function that has access to variables in its outer (enclosing) scope even after the outer function returns.

Basic Example:

function outer(x) {
    // Outer function's variable
    
    function inner(y) {
        // Inner function has access to 'x'
        return x + y;
    }
    
    return inner;
}

const add5 = outer(5);
console.log(add5(3)); // 8

Practical Use Cases:

Counter Example:

function createCounter() {
    let count = 0;
    
    return {
        increment: () => ++count,
        decrement: () => --count,
        getCount: () => count
    };
}

const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.getCount());  // 1

The 'this' Keyword

How does 'this' work in JavaScript?

The value of this depends on how a function is called.

1. Global Context:

console.log(this); // Window object (browser) or global (Node.js)

2. Object Method:

const obj = {
    name: "John",
    greet() {
        console.log(this.name); // "John"
    }
};
obj.greet();

3. Arrow Functions:

const obj = {
    name: "John",
    greet: () => {
        console.log(this.name); // undefined (inherits from parent scope)
    }
};

4. Call, Apply, Bind:

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

const person = { name: "Alice" };

greet.call(person);    // "Hello, Alice"
greet.apply(person);   // "Hello, Alice"
const boundGreet = greet.bind(person);
boundGreet();          // "Hello, Alice"

Objects & Properties

How do you work with objects in JavaScript?

Creating Objects:

// Object literal
const person = {
    name: "John",
    age: 30
};

// Constructor function
function Person(name, age) {
    this.name = name;
    this.age = age;
}
const john = new Person("John", 30);

// Object.create()
const personProto = {
    greet() { console.log(`Hi, I'm ${this.name}`); }
};
const alice = Object.create(personProto);
alice.name = "Alice";

Object Methods:

Prototypes & Inheritance

How does prototypal inheritance work in JavaScript?

Every JavaScript object has a prototype. Objects inherit properties and methods from their prototype.

Prototype Chain:

function Animal(name) {
    this.name = name;
}

Animal.prototype.speak = function() {
    console.log(`${this.name} makes a sound`);
};

function Dog(name, breed) {
    Animal.call(this, name);
    this.breed = breed;
}

// Set up inheritance
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.bark = function() {
    console.log(`${this.name} barks`);
};

const dog = new Dog("Buddy", "Golden Retriever");
dog.speak(); // "Buddy makes a sound"
dog.bark();  // "Buddy barks"

ES6 Classes (Syntactic Sugar):

class Animal {
    constructor(name) {
        this.name = name;
    }
    
    speak() {
        console.log(`${this.name} makes a sound`);
    }
}

class Dog extends Animal {
    constructor(name, breed) {
        super(name);
        this.breed = breed;
    }
    
    bark() {
        console.log(`${this.name} barks`);
    }
}

Event Loop

How does the JavaScript Event Loop work?

JavaScript is single-threaded but uses an event loop to handle asynchronous operations.

Components:

Example:

console.log("1");

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

console.log("3");

// Output: 1, 3, 2

Microtasks vs Macrotasks:

Promises

What are Promises in JavaScript?

A Promise is an object representing the eventual completion or failure of an asynchronous operation.

Promise States:

Creating Promises:

const myPromise = new Promise((resolve, reject) => {
    const success = true;
    
    setTimeout(() => {
        if (success) {
            resolve("Operation successful!");
        } else {
            reject("Operation failed!");
        }
    }, 1000);
});

// Using the promise
myPromise
    .then(result => console.log(result))
    .catch(error => console.error(error))
    .finally(() => console.log("Cleanup"));

Promise Methods:

Async/Await

How does async/await work?

Async/await is syntactic sugar over Promises, making asynchronous code look more like synchronous code.

Basic Usage:

async function fetchData() {
    try {
        const response = await fetch('/api/data');
        const data = await response.json();
        return data;
    } catch (error) {
        console.error('Error:', error);
        throw error;
    }
}

// Usage
fetchData()
    .then(data => console.log(data))
    .catch(error => console.error(error));

Parallel Execution:

async function fetchMultiple() {
    // Sequential (slower)
    const data1 = await fetch('/api/data1');
    const data2 = await fetch('/api/data2');
    
    // Parallel (faster)
    const [response1, response2] = await Promise.all([
        fetch('/api/data1'),
        fetch('/api/data2')
    ]);
}

Error Handling:

async function handleErrors() {
    try {
        const result = await fetch('/api/data');
        
        if (!result.ok) {
            throw new Error(`HTTP error! status: ${result.status}`);
        }
        
        return await result.json();
    } catch (error) {
        console.error('Fetch failed:', error);
        // Handle different error types
        if (error.name === 'TypeError') {
            // Network error
            console.log('Network error occurred');
        }
        throw error;
    }
}

Debouncing & Throttling

What is the difference between debouncing and throttling?

Debouncing:

Delays execution until after a specified time has passed since the last invocation.

function debounce(func, delay) {
    let timeoutId;
    
    return function(...args) {
        clearTimeout(timeoutId);
        
        timeoutId = setTimeout(() => {
            func.apply(this, args);
        }, delay);
    };
}

// Usage
const searchInput = document.getElementById('search');
const debouncedSearch = debounce((value) => {
    console.log('Searching for:', value);
}, 300);

searchInput.addEventListener('input', (e) => {
    debouncedSearch(e.target.value);
});

Throttling:

Limits execution to at most once per specified time interval.

function throttle(func, limit) {
    let inThrottle;
    
    return function(...args) {
        if (!inThrottle) {
            func.apply(this, args);
            inThrottle = true;
            
            setTimeout(() => {
                inThrottle = false;
            }, limit);
        }
    };
}

// Usage
const throttledScroll = throttle(() => {
    console.log('Scroll event handled');
}, 100);

window.addEventListener('scroll', throttledScroll);

DOM Manipulation

How do you manipulate the DOM in JavaScript?

Selecting Elements:

// By ID
const element = document.getElementById('myId');

// By Class
const elements = document.getElementsByClassName('myClass');
const element = document.querySelector('.myClass');
const allElements = document.querySelectorAll('.myClass');

// By Tag
const paragraphs = document.getElementsByTagName('p');

Creating and Modifying Elements:

// Create element
const div = document.createElement('div');
div.textContent = 'Hello World';
div.className = 'my-class';
div.setAttribute('data-id', '123');

// Append to DOM
document.body.appendChild(div);

// Modify existing element
const existing = document.querySelector('#existing');
existing.innerHTML = 'Updated content';
existing.style.backgroundColor = 'blue';

Event Handling:

// Add event listener
button.addEventListener('click', function(event) {
    event.preventDefault();
    console.log('Button clicked!');
});

// Remove event listener
button.removeEventListener('click', handler);

// Event delegation
document.addEventListener('click', function(event) {
    if (event.target.classList.contains('button')) {
        console.log('Delegated click');
    }
});

Error Handling

How do you handle errors in JavaScript?

Try-Catch-Finally:

try {
    // Code that might throw an error
    const result = JSON.parse(invalidJSON);
} catch (error) {
    // Handle the error
    console.error('Parsing failed:', error.message);
} finally {
    // Always executed
    console.log('Cleanup completed');
}

Custom Error Types:

class ValidationError extends Error {
    constructor(message, field) {
        super(message);
        this.name = 'ValidationError';
        this.field = field;
    }
}

function validateEmail(email) {
    if (!email.includes('@')) {
        throw new ValidationError('Invalid email format', 'email');
    }
}

try {
    validateEmail('invalid-email');
} catch (error) {
    if (error instanceof ValidationError) {
        console.log(`Validation failed for ${error.field}: ${error.message}`);
    }
}

Global Error Handling:

// Handle uncaught errors
window.addEventListener('error', function(event) {
    console.error('Global error:', event.error);
});

// Handle unhandled promise rejections
window.addEventListener('unhandledrejection', function(event) {
    console.error('Unhandled promise rejection:', event.reason);
    event.preventDefault(); // Prevent default browser behavior
});

ES6+ Modern Features

What are the key ES6+ features?

Arrow Functions:

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

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

// With single parameter (parentheses optional)
const square = x => x * x;

// With block body
const processData = (data) => {
    const processed = data.map(item => item * 2);
    return processed.filter(item => item > 10);
};

Destructuring:

// Array destructuring
const [first, second, ...rest] = [1, 2, 3, 4, 5];

// Object destructuring
const { name, age, city = 'Unknown' } = person;

// Function parameter destructuring
function greet({ name, age }) {
    console.log(`Hello ${name}, you are ${age} years old`);
}

Template Literals:

const name = 'John';
const age = 30;

// Multi-line strings
const message = `Hello ${name},
You are ${age} years old.
Welcome to JavaScript!`;

// Tagged templates
function highlight(strings, ...values) {
    return strings.reduce((result, string, i) => {
        const value = values[i] ? `${values[i]}` : '';
        return result + string + value;
    }, '');
}

Spread and Rest Operators:

// Spread operator
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]

const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 }; // { a: 1, b: 2, c: 3 }

// Rest parameters
function sum(...numbers) {
    return numbers.reduce((total, num) => total + num, 0);
}

JavaScript Best Practices

What are some JavaScript coding best practices?

Performance Optimization

How can you optimize JavaScript performance?

Code Optimization:

Memory Management: