DEV Community

Cover image for Top 20 Advanced JavaScript Interview Questions and Answers for Seasoned Engineers
GreatFrontEnd Team
GreatFrontEnd Team

Posted on

Top 20 Advanced JavaScript Interview Questions and Answers for Seasoned Engineers

JavaScript interviews for seasoned developers are about much more than just ticking off syntax basics. They delve into complex scenarios that test your ability to craft sophisticated solutions and architect high-performing systems. If you’re looking to move up the ladder or land a coveted position, acing these 20 advanced JavaScript interview questions will strengthen your expertise—and make you stand out from the crowd.

💡 Ready to ace your JavaScript interviews? Join more than 500,000 frontend engineers on GreatFrontEnd — the ultimate hub for mastering frontend interview questions.

Leverage materials created by ex-FAANG interviewers, ensuring you practice with the best resources available. Features an in-browser coding platform, along with official solutions and tests for every challenge! 💡

🚀 Discover 440+ JavaScript questions with answers here →

🚀 Discover 380+ TypeScript questions with answers here →

1. Why Doesn't function foo(){ }(); Work as an IIFE? How Can We Fix It?

An IIFE (Immediately Invoked Function Expression) runs immediately after being defined. However, the code function foo(){ }(); doesn’t work as an IIFE because the JavaScript parser splits it into two parts:

  1. function foo(){ } — This is treated as a function declaration, not an expression.
  2. () — This tries to invoke a function, but it ends up being invalid syntax when applied to a declaration.

This results in a SyntaxError, as function declarations can't be invoked in this way.

To fix this, you need to convert the declaration into an expression. You can do this by wrapping the function in parentheses:

(function foo(){ })(); // Now it's a valid IIFE
Enter fullscreen mode Exit fullscreen mode

Why It Matters in Interviews

IIFEs are a foundational concept in JavaScript, often used to create private scopes or execute code immediately. Understanding the distinction between function declarations and expressions shows your grasp of JavaScript's syntax rules and nuances, which is essential for writing clean and error-free code.

Bonus Insights

  • Why Use IIFEs? They’re great for avoiding polluting the global scope, especially in older JavaScript patterns before ES6 modules became standard.
  • Naming Inside IIFEs: Naming the function as in function foo(){} creates a named function expression, making debugging easier because the function has a name in stack traces.

Explore why doesn't function foo(){ }(); work as an IIFE? How can we fix it on GreatFrontEnd

2. What Are Iterators and Generators in JavaScript, and Why Are They Useful?

In JavaScript, iterators and generators provide efficient ways to handle sequences and manage execution flow dynamically. They’re essential for working with data structures and asynchronous workflows.

Iterators

An iterator is an object that provides a next() method to traverse a sequence. Each call to next() returns an object with two properties:

  • value — The next value in the sequence.
  • done — A boolean indicating if the sequence is complete.

Example: Creating a Custom Iterator for a Number Range

You can define custom iterators by implementing the [Symbol.iterator]() method:

class Range {
  constructor(start, end) {
    this.start = start;
    this.end = end;
  }

  [Symbol.iterator]() {
    let current = this.start;
    const end = this.end;
    return {
      next() {
        if (current <= end) {
          return { value: current++, done: false };
        } else {
          return { value: undefined, done: true };
        }
      },
    };
  }
}

const range = new Range(1, 3);
for (const number of range) {
  console.log(number); // 1, 2, 3
}
Enter fullscreen mode Exit fullscreen mode

Generators

A generator is a function that can pause and resume execution. It uses the yield keyword to produce values one at a time, making it perfect for lazy evaluation or asynchronous workflows.

Example: Using a Generator for a Number Range

Generators simplify iterators with less boilerplate:

class Range {
  constructor(start, end) {
    this.start = start;
    this.end = end;
  }

  *[Symbol.iterator]() {
    let current = this.start;
    while (current <= this.end) {
      yield current++;
    }
  }
}

const range = new Range(1, 3);
for (const number of range) {
  console.log(number); // 1, 2, 3
}
Enter fullscreen mode Exit fullscreen mode

Advanced Example: Fetching Data in Batches with Generators

Generators are excellent for handling streams, such as paginated API data:

async function* fetchDataInBatches(url, batchSize = 10) {
  let startIndex = 0;
  while (true) {
    const response = await fetch(`${url}?start=${startIndex}&limit=${batchSize}`);
    const data = await response.json();
    if (data.length === 0) break;
    yield data;
    startIndex += batchSize;
  }
}

const dataGenerator = fetchDataInBatches('https://api.example.com/data');
for await (const batch of dataGenerator) {
  console.log(batch);
}
Enter fullscreen mode Exit fullscreen mode

Why It Matters in Interviews

Iterators and generators highlight your understanding of JavaScript's advanced features. Mastery of these concepts shows you can efficiently work with sequences, build custom iteration logic, and handle asynchronous tasks in real-world scenarios.

Bonus Insights

  • Why Generators Shine: They allow you to create iterators with less code, making them more readable and maintainable.
  • Lazy Evaluation: Generators only compute values when needed, reducing memory overhead for large datasets or infinite sequences.
  • Real-World Use Cases: Examples include streaming data, asynchronous workflows, and handling paginated results.

Explore what iterators and Generators are in JavaScript, and why they are useful on GreatFrontEnd

3. What Are JavaScript Object Property Flags and Descriptors?

JavaScript object property flags and descriptors give you precise control over how object properties behave. They let you manage access, modification, visibility, and configurability of properties.

Property Flags

Property flags are settings that control a property's behavior. You can define these flags using Object.defineProperty(). The key flags are:

  • writable: Determines if the property can be modified. Default is true.
  • enumerable: Specifies if the property shows up during enumeration (e.g., in a for...in loop). Default is true.
  • configurable: Indicates whether the property can be deleted or its attributes changed. Default is true.

Property Descriptors

Property descriptors contain detailed metadata about a property, including its value and the associated flags. You can inspect them using Object.getOwnPropertyDescriptor() and set them with Object.defineProperty().

Example:

let user = { name: 'John Doe' };
let descriptor = Object.getOwnPropertyDescriptor(user, 'name');
console.log(descriptor);
// {value: "John Doe", writable: true, enumerable: true, configurable: true}
Enter fullscreen mode Exit fullscreen mode

Manipulating Property Flags

1. writable

Controls whether the property value can be changed.

If false, writing to the property silently fails in non-strict mode or throws a TypeError in strict mode.

const obj = {};
Object.defineProperty(obj, 'name', { writable: false, value: 'John Doe' });
console.log(obj.name); // John Doe
obj.name = 'Jane Doe'; // TypeError in strict mode
Enter fullscreen mode Exit fullscreen mode

2. enumerable

Determines if the property is included in for...in loops and Object.keys().

const obj = {};
Object.defineProperty(obj, 'name', {
  enumerable: false,
  value: 'John Doe',
});
for (const prop in obj) console.log(prop); // No output
Enter fullscreen mode Exit fullscreen mode

3. configurable

Specifies if the property can be deleted or its flags altered.

If false, attempts to delete or reconfigure it fail silently in non-strict mode or throw a TypeError in strict mode.

const obj = {};
Object.defineProperty(obj, 'name', {
  configurable: false,
  value: 'John Doe',
});
delete obj.name; // TypeError in strict mode
Enter fullscreen mode Exit fullscreen mode

Why It Matters in Interviews

Understanding property flags and descriptors shows you can create robust, secure, and predictable objects. These are crucial for designing APIs, managing encapsulation, and creating read-only or hidden properties in your code.

Bonus Insights

  • Practical Use Cases: Use flags to create immutable objects, hide properties, or optimize performance by reducing unnecessary enumerations.
  • Default Behavior: Properties created with plain assignment have all flags set to true, making them fully writable, enumerable, and configurable.
  • Advanced Applications: Property descriptors are frequently used in frameworks and libraries for tasks like defining reactive properties or setting up proxies.

Explore what JavaScript object property flags and descriptors are on GreatFrontEnd

4. What Are JavaScript Polyfills?

Polyfills are scripts that bring modern JavaScript features to older browsers that don’t support them. They allow developers to use the latest language features while ensuring compatibility with outdated environments.

How Polyfills Work

Polyfills check for missing features in the environment and provide custom implementations using existing JavaScript. For example, the Array.prototype.includes() method is unsupported in older browsers like Internet Explorer 11. A polyfill could look like this:

if (!Array.prototype.includes) {
  Array.prototype.includes = function (searchElement) {
    for (var i = 0; i < this.length; i++) {
      if (this[i] === searchElement) return true;
    }
    return false;
  };
}
Enter fullscreen mode Exit fullscreen mode

Steps to Implement a Polyfill

  1. Detect the Missing Feature: Use tools like typeof, in, or window to check for feature availability.
  2. Create the Fallback: Write a custom implementation of the feature.
  3. Test It: Verify that the polyfill works in the target browsers.
  4. Apply Conditionals: Use feature detection to only apply the polyfill where needed.

Popular Libraries and Services

  • core-js: A comprehensive library for ECMAScript polyfills.
import 'core-js/actual/array/flat-map';
[1, 2].flatMap((it) => [it, it]); // => [1, 1, 2, 2]
Enter fullscreen mode Exit fullscreen mode
  • Polyfill.io: Dynamically serves polyfills based on the browser and requested features.
<script src="https://polyfill.io/v3/polyfill.min.js"></script>
Enter fullscreen mode Exit fullscreen mode

Why It Matters in Interviews

  • Modern Practices: Shows knowledge of ensuring backward compatibility for web applications.
  • Problem Solving: Demonstrates the ability to address browser-specific challenges.
  • Technical Breadth: Understanding polyfills showcases a grasp of JavaScript evolution and how to bridge gaps in support.

Bonus Insights

  • Performance Considerations: Minimize polyfill usage to reduce bundle size and load times.
  • Selective Loading: Only load polyfills for browsers that need them.
  • Real-World Impact: Polyfills are crucial for maintaining functionality in legacy environments, particularly in enterprise or global applications.

Explore what JavaScript polyfills are for on GreatFrontEnd

5. What Are Server-Sent Events (SSE)?

Server-Sent Events (SSE) allow servers to push real-time updates to web clients over a single, persistent HTTP connection. Unlike client polling, SSE streams updates efficiently, reducing overhead for applications that require continuous data delivery.

How SSE Works

  1. Client Initialization: The client creates an EventSource object with the URL of the server endpoint.
  2. Server Response: The server sends an event stream by setting appropriate headers.
  3. Event Format: Events use fields like event, data, and id for structured communication.
  4. Client Event Handling: The EventSource object dispatches events that can be captured with listeners.
  5. Automatic Reconnection: The client retries connections and resumes from the last event ID if the connection drops.

Key Features of SSE

  • Unidirectional Communication: The server sends data to the client, but not vice versa.
  • Automatic Retry: The client reconnects if the stream is interrupted.
  • Text-Only Data: SSE supports streaming plain text data.
  • Custom Event Types: Enables categorization of messages for better organization.
  • Built-in Browser Support: Supported by most modern browsers without additional libraries.
  • Efficient Reconnection: Uses the Last-Event-Id header to resume streams seamlessly.

Implementing SSE

Client-Side:

const eventSource = new EventSource('/sse');
eventSource.onmessage = (event) => console.log('New message:', event.data);
Enter fullscreen mode Exit fullscreen mode

Server-Side (Node.js):

const http = require('http');

http
  .createServer((req, res) => {
    if (req.url === '/sse') {
      // Set headers for SSE
      res.writeHead(200, {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        Connection: 'keep-alive',
      });

      // Function to send messages
      const sendMessage = (message) => {
        res.write(`data: ${message}\n\n`); // Messages end with a double line break
      };

      // Send periodic updates
      const intervalId = setInterval(() => {
        sendMessage(`Current time: ${new Date().toLocaleTimeString()}`);
      }, 5000);

      // Handle client disconnection
      req.on('close', () => {
        clearInterval(intervalId);
        res.end();
      });
    } else {
      res.writeHead(404);
      res.end();
    }
  })
  .listen(8080, () => {
    console.log('SSE server running on port 8080');
  });
Enter fullscreen mode Exit fullscreen mode

SSE is ideal for real-time updates like live scores, notifications, or stock price feeds where unidirectional communication suffices.

Why It Matters in Interviews

  • Understanding Real-Time Communication: SSE demonstrates how to deliver updates efficiently without constant client polling.
  • Alternative to WebSockets: Shows knowledge of when to use SSE instead of WebSockets for simpler unidirectional data flows.
  • Implementation Knowledge: Tests understanding of client-server interaction and HTTP protocols.

Bonus Insights

  • Simplicity Over WebSockets: While WebSockets offer bidirectional communication, SSE is simpler to implement for server-to-client streams.
  • Applications: Useful for dashboards, live notifications, and streaming updates.
  • Browser Support: Ensure compatibility for use cases where SSE might not be natively supported (e.g., older browsers).

Explore what server-sent events are on GreatFrontEnd

6. What Are Workers in JavaScript Used For?

JavaScript workers enable background processing by running scripts in separate threads, offloading heavy tasks from the main thread. This helps keep the user interface responsive during CPU-intensive operations. There are three main types of workers in JavaScript: Web Workers, Service Workers, and Shared Workers.

Web Workers / Dedicated Workers

  • Purpose: Handle computationally heavy tasks (e.g., data processing) to avoid blocking the main thread.
  • Communication: Use postMessage() and onmessage for message passing.
  • Restrictions: No direct DOM access.
  • Lifecycle: Runs until explicitly terminated or the main script unloads.

Example: Web Worker in Action

main.js:

if (window.Worker) {
  const myWorker = new Worker('worker.js');

  myWorker.postMessage('Hello, Worker!');

  myWorker.onmessage = function (event) {
    console.log('Message from Worker:', event.data);
  };

  myWorker.onerror = function (error) {
    console.error('Error from Worker:', error);
  };
}
Enter fullscreen mode Exit fullscreen mode

worker.js:

onmessage = function (event) {
  console.log('Message from Main Script:', event.data);

  const result = event.data + ' - Processed by Worker';

  postMessage(result);
};
Enter fullscreen mode Exit fullscreen mode

Service Workers

  • Purpose: Serve as a network proxy, caching resources, enabling offline capabilities, and managing push notifications.
  • Lifecycle: Includes installation, activation, and updates, all managed by the browser.
  • Security: Cannot directly interact with the DOM.

Example: Service Worker Basics

main.js:

if ('serviceWorker' in navigator) {
  navigator.serviceWorker
    .register('/service-worker.js')
    .then((registration) => {
      console.log('Service Worker registered:', registration);
    })
    .catch((err) => {
      console.log('Service Worker registration failed:', err);
    });
}
Enter fullscreen mode Exit fullscreen mode

service-worker.js:

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then((response) => {
      return response || fetch(event.request);
    }),
  );
});
Enter fullscreen mode Exit fullscreen mode

Shared Workers

  • Purpose: Facilitate shared state and communication between multiple browser contexts like tabs, iframes, or windows.
  • Use Case: Share resources efficiently across related scripts in the same origin.

Considerations and Limitations

  • Same-Origin Policy: Workers must adhere to same-origin rules.
  • No DOM Access: All interaction with the main thread happens through message passing.
  • Performance Overhead: Managing workers requires resources; use them only when necessary.
  • Error Handling: Ensure robust error handling in worker scripts.

Why It Matters in Interviews

  • Performance Optimization: Shows knowledge of keeping UIs smooth by offloading tasks to workers.
  • Real-World Applications: Demonstrates understanding of features like offline capabilities and shared state management.
  • Technical Depth: Tests familiarity with JavaScript’s concurrency model and browser security policies.

Bonus Insights

  • Web Workers: Ideal for tasks like data parsing, encoding, or simulations that don’t require UI updates.
  • Service Workers: Critical for building modern web apps with offline support and progressive enhancement.
  • Shared Workers: Useful in scenarios like multi-tab chat applications or resource sharing across windows.

Explore what workers in JavaScript are used for on GreatFrontEnd

7. What is "use strict";? Advantages and Disadvantages

"use strict"; is a directive introduced in ECMAScript 5 (ES5) to enforce stricter rules and error handling in JavaScript. It helps catch common mistakes, makes code more secure, and improves compatibility with future updates.

How to Use "use strict"

  1. Global Scope: Add the directive at the beginning of a file to enforce strict mode throughout the entire script.

    'use strict';
    function add(a, b) {
      return a + b;
    }
    
  2. Local Scope: Add the directive at the start of a function to apply strict mode only within that function.

    function myFunction() {
      'use strict';
      // Strict mode applies here
    }
    

Key Features of Strict Mode

  1. Error Prevention:
    • Disallows undeclared variables.
    • Prevents assignments to non-writable properties.
    • Restricts the use of reserved keywords for identifiers.
  2. Improved Security:
    • Disallows deprecated features like arguments.caller and arguments.callee.
    • Restricts eval() to prevent declarations in the calling scope.
  3. Future Compatibility:
    • Helps write cleaner, more maintainable code that aligns with modern JavaScript standards.

Example: Preventing Global Variables

// Without strict mode
function defineNumber() { count = 123; }
defineNumber();
console.log(count); // Logs: 123

// With strict mode
'use strict';
function strictFunc() {
  strictVar = 123; // ReferenceError: strictVar is not defined
}
strictFunc();
console.log(strictVar); // ReferenceError
Enter fullscreen mode Exit fullscreen mode

When Is It Necessary?

  • Modules: ES6 modules and Node.js modules are automatically in strict mode.
  • Classes: Code inside class definitions also runs in strict mode by default.

Although it’s unnecessary in these contexts, "use strict"; is still useful for older codebases or scripts where strict mode isn’t enforced automatically.

Why It Matters in Interviews

  • Error Detection: Demonstrates understanding of JavaScript's common pitfalls and how to avoid them.
  • Security Awareness: Shows a candidate’s ability to write safe, maintainable, and modern JavaScript code.
  • Backward Compatibility: Highlights knowledge of working with older environments where strict mode isn’t the default.

Bonus Insights

  • Code Quality: Strict mode enforces better coding practices, reducing bugs and improving maintainability.
  • Learning Tool: It’s great for beginners to learn proper variable declarations and avoid accidental global variables.
  • Performance: While strict mode doesn’t directly improve performance, its cleaner syntax and error checking can lead to better-optimized code.

Explore what "use strict" is and its advantages and disadvantages on GreatFrontEnd

8. Implementing Secure Authentication and Authorization in JavaScript Applications

Securing authentication and authorization in JavaScript applications is crucial for protecting user data and preventing unauthorized access. Here are key practices to ensure robust security:

Best Practices for Authentication and Authorization

  1. Use HTTPS: Encrypt all data in transit to prevent interception by attackers.

  2. Secure Token Storage:

    • Store tokens securely in localStorage, sessionStorage, or secure cookies.
    • Avoid storing sensitive data in non-secure areas like plain JavaScript variables.
  3. Token-Based Authentication:

    • Use JSON Web Tokens (JWT) for secure, stateless authentication.
    • Validate tokens on the server to confirm authenticity and expiration.
  4. Third-Party Authentication:

    • Leverage libraries like OAuth for integrating trusted third-party authentication providers (e.g., Google, Facebook).
  5. Enforce Role-Based Access Control (RBAC):

    • Define roles and permissions to restrict user actions based on their level of access.
    • Check user roles before granting access to sensitive features or routes.
  6. Server-Side Validation:

    • Always validate sensitive requests on the server, regardless of client-side checks.
  7. Prevent Token Leakage:

    • Use secure, HttpOnly cookies for tokens to protect them from XSS attacks.

Why It Matters in Interviews

  • Practical Knowledge: Demonstrates understanding of secure coding practices in real-world applications.
  • Security Awareness: Shows the ability to identify and mitigate common vulnerabilities, such as token theft or unauthorized access.
  • Scalability: Highlights understanding of modern, scalable approaches like token-based and third-party authentication.

Bonus Insights

  • Protect Against CSRF: Implement CSRF tokens or rely on same-site cookies to safeguard against cross-site request forgery.
  • Refresh Token Strategy: Use short-lived access tokens with long-lived refresh tokens for enhanced security.
  • Avoid Sensitive Storage: Never store tokens in plain text files or hard-code them into the application.

Explore how to implement secure authentication and authorization in JavaScript applications on GreatFrontEnd

9. How Can You Optimize DOM Manipulation for Better Performance?

Efficient DOM manipulation is key to ensuring a smooth user experience. By minimizing direct DOM interactions and adopting best practices, you can significantly boost performance.

Best Practices for Optimizing DOM Manipulation

  1. Batch DOM Updates:

    • Group multiple changes into a single update to avoid repeated reflows and repaints.
    • Use tools like documentFragment to prepare updates before adding them to the DOM.
  2. Leverage Virtual DOM:

    • Use frameworks like React or Vue that employ a virtual DOM to minimize costly DOM operations.
    • The virtual DOM calculates changes before updating the real DOM.
  3. Avoid Layout Thrashing:

    • Separate DOM reads (e.g., offsetHeight) from writes (e.g., style) to prevent repeated reflows.
    • Batch reads and writes together for efficient updates.
  4. Use requestAnimationFrame:

    • Optimize animations by scheduling updates with requestAnimationFrame, which synchronizes with the browser's refresh rate.
  5. Reduce Selector Complexity:

    • Use simpler, faster selectors like IDs (#id) or class names (.class) over complex CSS selectors.
  6. Debounce and Throttle:

    • For event-driven updates (e.g., resizing, scrolling), use debounce or throttle techniques to limit frequency.

Why It Matters in Interviews

  • Performance Focus: Shows understanding of how DOM interactions impact rendering and performance.
  • Real-World Relevance: Highlights ability to optimize heavy DOM operations in scalable applications.
  • Framework Familiarity: Demonstrates awareness of virtual DOM benefits and how modern frameworks solve performance challenges.

Bonus Insights

  • Memory Management: Remove unused DOM elements to free up memory and improve performance.
  • Lazy Loading: Use lazy loading for images or data-heavy elements to improve initial load time.
  • Profiling Tools: Leverage browser dev tools to identify performance bottlenecks in DOM operations.

Explore how to optimize DOM manipulation for better performance on GreatFrontEnd

10. How Can You Optimize Network Requests for Better Performance?

Optimizing network requests is crucial for improving load times and overall user experience. By minimizing requests, using efficient caching, and compressing data, you can significantly enhance application performance.

Best Practices for Optimizing Network Requests

  1. Reduce Request Count:

    • Combine CSS and JavaScript files where possible.
    • Use image sprites or SVGs to reduce the number of asset requests.
  2. Enable Caching:

    • Use Cache-Control and ETags headers to allow browsers to store static assets locally.
    • Implement service workers for caching dynamic assets and enabling offline functionality.
  3. Compress Data:

    • Enable Gzip or Brotli compression on your server to reduce the size of transmitted files.
    • Use compressed image formats (e.g., WebP) for smaller file sizes without quality loss.
  4. Leverage HTTP/2:

    • Take advantage of multiplexing in HTTP/2 to send multiple requests over a single connection, reducing latency.
  5. Optimize API Calls:

    • Use pagination or lazy loading for large datasets to load only what is needed.
    • Minimize redundant or duplicate requests by batching them together.
  6. Use Content Delivery Networks (CDNs):

    • Serve static assets from a CDN to reduce latency by delivering files from servers closer to the user.

Why It Matters in Interviews

  • Performance-Oriented Thinking: Shows an understanding of real-world optimization techniques to improve application responsiveness.
  • User-Centric Design: Demonstrates the ability to create faster and more efficient web experiences.
  • Knowledge of Modern Standards: Highlights familiarity with technologies like HTTP/2, caching strategies, and compression.

Bonus Insights

  • Service Workers: Combine caching strategies with service workers for better offline support and improved loading speeds.
  • Prefetching and Preloading: Use <link rel="prefetch"> or <link rel="preload"> to prioritize critical resources.
  • Monitoring Tools: Leverage tools like Lighthouse and Chrome DevTools to identify bottlenecks in network performance.

Explore how to optimize network requests for better performance on GreatFrontEnd

11. How Can You Prevent Clickjacking Attacks?

Clickjacking is a security vulnerability where attackers trick users into interacting with hidden or deceptive elements embedded in iframes. Preventing this requires controlling how your content is embedded on other sites.

Key Strategies to Prevent Clickjacking

  1. Use X-Frame-Options Header:

    • Add the X-Frame-Options HTTP header to restrict iframe usage:
    • DENY: Prevents your site from being embedded in any iframe.
    • SAMEORIGIN: Allows embedding only on pages from the same origin.
    X-Frame-Options: DENY
    
  2. Content-Security-Policy (CSP):

    • Use the frame-ancestors directive in CSP headers to control which origins can embed your site.
    • Example configuration to allow only the same origin:
    Content-Security-Policy: frame-ancestors 'self';
    
  3. Frame-Busting Scripts:

    • As an additional layer, use JavaScript to prevent your site from being embedded:
    if (window.top !== window.self) {
              window.top.location = window.self.location;
    }
    

Note: This approach is less effective against modern attacks and should supplement header-based protections.

Why It Matters in Interviews

  • Security Awareness: Demonstrates an understanding of web vulnerabilities and mitigation techniques.
  • Practical Knowledge: Highlights familiarity with HTTP headers and browser security mechanisms.
  • Real-World Relevance: Shows you can secure applications against common attacks targeting user interactions.

Bonus Insights

  • Browser Support: Most modern browsers support X-Frame-Options and CSP headers, making them effective defenses.
  • Layered Security: Combine these strategies with other security measures like CORS and input validation for comprehensive protection.
  • Testing Tools: Use tools like OWASP ZAP or browser dev tools to verify your headers are properly configured.

Explore how to prevent clickjacking attacks on GreatFrontEnd

12. How Do You Validate Form Elements Using the Constraint Validation API?

The Constraint Validation API provides an easy way to validate form elements directly in JavaScript. It includes properties like validity and validationMessage and methods like checkValidity() and setCustomValidity() to manage and display validation errors effectively.

Example: Using the Constraint Validation API

Here’s a simple example of form validation:

const input = document.querySelector('input');

if (input.checkValidity()) {
  console.log('Input is valid');
} else {
  console.log(input.validationMessage);
}
Enter fullscreen mode Exit fullscreen mode

Key Features of the Constraint Validation API

  1. checkValidity():
    • Checks if the input element meets all validation rules (e.g., required, minlength).
    • Returns true if valid, otherwise false.
  2. validity:
    • Provides detailed validation status as a ValidityState object, such as valueMissing or typeMismatch.
  3. validationMessage:
    • Returns the error message associated with the first invalid rule.
  4. setCustomValidity():
    • Allows custom error messages to be set for specific validation failures.

Example with Custom Error Messages


    const input = document.querySelector('input');

    input.addEventListener('input', () => {
      if (input.value.length < 5) {
        input.setCustomValidity('Input must be at least 5 characters long');
      } else {
        input.setCustomValidity('');
      }

      console.log(input.validationMessage);
    });

Enter fullscreen mode Exit fullscreen mode

Why It Matters in Interviews

  • User Experience: Demonstrates your ability to implement intuitive and robust form validation.
  • Built-in Efficiency: Highlights knowledge of browser-native validation features, reducing the need for custom logic.
  • Error Management: Shows understanding of handling validation states dynamically.

Bonus Insights

  • Accessibility: Browser-native validation messages are automatically accessible to assistive technologies.
  • Cross-Browser Behavior: The API works consistently across modern browsers.
  • Enhancing Validation: Combine Constraint Validation API with additional custom validation logic for advanced use cases.

Explore how to validate form elements using the Constraint Validation API on GreatFrontEnd

13. How Does Hoisting Affect Function Declarations and Expressions?

Hoisting is a JavaScript behavior where variable and function declarations are moved to the top of their scope during compilation. This allows you to use certain declarations before their actual definition in the code. However, the way hoisting works differs for function declarations and expressions.

Key Differences Between Function Declarations and Expressions

  1. Function Declarations:

    • Fully hoisted to the top of their scope.
    • Can be called before they are defined in the code.
      console.log(foo()); // Works fine
      function foo() {
        return 'Hello';
      }
    
  2. Function Expressions:

    • Only the variable is hoisted, not its assigned value.
    • Results in a TypeError if called before the assignment.
    console.log(bar()); // Throws TypeError: bar is not a function
    var bar = function () {
      return 'Hello';
    };
    

Why It Matters in Interviews

  • Core JavaScript Knowledge: Shows understanding of one of JavaScript’s fundamental behaviors.
  • Debugging Skills: Helps in identifying common issues caused by hoisting, especially in large codebases.
  • Practical Relevance: Demonstrates the importance of function declarations versus expressions in real-world scenarios.

Bonus Insights

  • Block Scope and Hoisting:
    • Variables declared with let and const are also hoisted, but they remain in the "temporal dead zone" until the code execution reaches their declaration.
  • Best Practices:
    • Use function declarations for cleaner and more predictable code.
    • Avoid relying on hoisting for better readability and fewer bugs.
  • Advanced Concepts:
    • Arrow functions follow the same hoisting behavior as function expressions.

Explore how hoisting affects function declarations and expressions on GreatFrontEnd

14. How Does JavaScript Garbage Collection Work?

JavaScript uses automatic garbage collection to manage memory by removing objects that are no longer needed. This process ensures efficient memory use without manual intervention. The two primary algorithms are mark-and-sweep and generational garbage collection.

How Garbage Collection Works

  1. Mark-and-Sweep:

    • Marking Phase: The garbage collector starts with root objects (e.g., global variables, active functions) and marks all objects that can be accessed from them as "in use."
    • Sweeping Phase: Unmarked objects are deemed unreachable and are removed, freeing memory for reuse.
  2. Generational Garbage Collection:

    • Objects are categorized by age into "generations."
    • Short-lived objects (e.g., temporary variables) remain in younger generations, which are cleaned up more frequently.
    • Long-lived objects move to older generations and are collected less often, improving efficiency for stable, long-lived data.

Different JavaScript engines, like V8 (used in Chrome and Node.js), may implement these strategies differently to optimize performance.

Why It Matters in Interviews

  • Understanding Fundamentals: Demonstrates a clear grasp of memory management in JavaScript.
  • Debugging Skills: Helps in identifying memory leaks and optimizing performance in web applications.
  • Real-World Applications: Shows readiness to handle resource-intensive scenarios like single-page applications or real-time updates.

Bonus Insights

  • Avoid Memory Leaks:
    • Ensure no unintended references to unused objects.
    • Be cautious with closures, event listeners, and global variables.
  • Optimization Tips:
    • Use WeakMap or WeakSet for objects that need weak references to prevent retention.
    • Monitor memory usage with tools like Chrome DevTools.
  • Advanced Concepts:
    • Learn about the event loop and how garbage collection affects asynchronous operations.

Explore how JavaScript garbage collection works on GreatFrontEnd

15. What Are Mocks and Stubs, and How Are They Used in Testing?

Mocks and stubs are essential tools in testing, allowing developers to isolate and verify code behavior. They simulate real objects or functions to control dependencies and ensure proper interactions.

Key Differences Between Mocks and Stubs

  1. Stubs:

    • Provide predefined responses to function calls.
    • Used to isolate the code being tested from external systems or dependencies.
    • Focus on returning controlled outputs without verifying interactions.
    const stub = sinon.stub();
    stub.withArgs(42).returns('stubbed response');
    
    console.log(stub(42)); // "stubbed response"
    
  2. Mocks:

    • Simulate real objects and track their interactions.
    • Verify specific behavior, such as whether a function was called or called with certain arguments.
    • Focus on ensuring correct interaction with dependencies.
    const mock = sinon.mock(obj);
    mock.expects('methodName').once().withArgs('test');
    
    obj.methodName('test'); // Passes if the method is called as expected
    mock.verify();
    

Why It Matters in Interviews

  • Testing Expertise: Demonstrates knowledge of isolating and testing code behavior in complex systems.
  • Problem-Solving Skills: Shows ability to identify and mock dependencies, making tests more reliable.
  • Real-World Relevance: Highlights understanding of creating robust test suites that scale with applications.

Bonus Insights

  • When to Use Stubs vs. Mocks:
    • Use stubs for simple scenarios where responses need to be controlled.
    • Use mocks for more complex tests requiring verification of method interactions.
  • Popular Libraries:
    • Tools like Sinon.js, Jest, and Mocha make working with mocks and stubs easier.
  • Best Practices:
    • Keep tests focused by mocking only the necessary parts of a dependency.
    • Avoid over-mocking, as it can make tests brittle and less reflective of real-world behavior.

Explore what mocks and stubs are and how they are used in testing on GreatFrontEnd

16. What Are Proxies in JavaScript Used For?

A proxy in JavaScript acts as an intermediary between your code and an object, allowing you to intercept and customize fundamental operations like property access, assignment, and method invocation.

Example: Basic Proxy Usage

Here’s an example of a proxy intercepting property access:

const myObject = {
  name: 'John',
  age: 42,
};

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

const proxiedObject = new Proxy(myObject, handler);

console.log(proxiedObject.name); // Logs: 'John'
// Accessed property "name"

console.log(proxiedObject.age); // Logs: 42
// Accessed property "age"
Enter fullscreen mode Exit fullscreen mode

Common Use Cases for Proxies

  1. Property Access Interception:
    • Customize behavior when properties are read or written.
  2. Validation:
    • Validate values before assigning them to object properties.
  3. Logging and Debugging:
    • Log interactions with objects to debug applications.
  4. Reactive Systems:
    • Automatically trigger updates or re-renders when properties change (e.g., in frameworks like Vue.js).
  5. Data Transformation:
    • Modify data being accessed or assigned dynamically.
  6. Mocking and Stubbing:
    • Create mock objects for testing with precise control over interactions.
  7. Function Invocation Interception:
    • Optimize or cache the results of frequently called methods.
  8. Dynamic Property Creation:
    • Define properties on-the-fly with default values or logic.

Why It Matters in Interviews

  • Versatile Use Cases: Demonstrates knowledge of advanced object manipulation for debugging, testing, or building reactive systems.
  • Core JavaScript Skills: Highlights understanding of fundamental concepts like property descriptors and object behavior.
  • Practical Application: Shows the ability to apply proxies to solve real-world problems in front-end frameworks or performance optimization.

Bonus Insights

  • Integration with Frameworks:
    • Proxies are foundational to frameworks like Vue.js, where they enable reactivity by tracking changes to data.
  • Browser Support:
    • Proxies are supported in modern browsers, but consider polyfills for legacy environments if necessary.
  • Performance Considerations:
    • Proxies can add overhead, so use them judiciously in performance-critical code.

Explore what proxies in JavaScript are used for on GreatFrontEnd

17. What Are the Advantages and Disadvantages of Writing JavaScript Code in a Language That Compiles to JavaScript?

Languages like TypeScript and CoffeeScript offer features beyond plain JavaScript by compiling to it. While they provide enhanced capabilities, they come with trade-offs.

Advantages

  1. Improved Syntax and Readability:

    • Cleaner and more structured syntax compared to raw JavaScript.
    • Encourages better coding practices.
  2. Type Safety:

    • TypeScript, for instance, introduces static typing, reducing runtime errors.
    • Catch bugs during development with type-checking.
  3. Better Tooling:

    • Enhanced editor features like IntelliSense and autocompletion.
    • Easier debugging with clear error messages.
  4. Modern Features:

    • Access to advanced language features before they are natively available in JavaScript.

Disadvantages

  1. Build Steps:

    • Requires a compilation process to convert code to JavaScript, adding complexity.
  2. Performance Overhead:

    • While the compiled JavaScript runs efficiently, the build process can slow down development workflows.
  3. Learning Curve:

    • Developers need to learn new syntax and tooling, which can be a barrier for teams unfamiliar with the language.
  4. Debugging Complexity:

    • Debugging may become harder due to discrepancies between the compiled JavaScript and the original source code.

Why It Matters in Interviews

  • Demonstrates Flexibility: Shows an understanding of modern development practices and tools like TypeScript.
  • Scalability Knowledge: Highlights awareness of how typed languages improve large-scale application maintainability.
  • Practical Understanding: Provides insights into trade-offs between developer productivity and added complexity.

Bonus Insights

  • When to Use:
    • TypeScript is ideal for large projects where type safety improves collaboration and reduces bugs.
    • CoffeeScript or similar languages may suit small teams focused on cleaner syntax.
  • Community Support:
    • Languages like TypeScript have strong ecosystems with widespread adoption, making them future-proof.
  • Compile-to-JS Trends:
    • Explore other compile-to-JavaScript options, like Dart or Elm, for unique features.

Explore advantages and disadvantages of writing JavaScript code in a language that compiles to JavaScript on GreatFrontEnd

18. What Are Some Techniques for Reducing Reflows and Repaints?

Reflows and repaints are costly rendering operations in the browser that can degrade performance, especially in visually dynamic applications. Reducing them ensures a smoother user experience.

Effective Techniques to Minimize Reflows and Repaints

  1. Batch DOM Manipulations:

    • Minimize direct DOM updates by grouping changes.
    • Use documentFragment to prepare updates before inserting them into the DOM.
  2. Use CSS Classes Instead of Inline Styles:

    • Update styles by toggling CSS classes rather than changing individual style properties directly.
  3. Optimize CSS Selectors:

    • Use simple, specific selectors for faster rendering (e.g., avoid overly complex descendant selectors).
  4. Use requestAnimationFrame:

    • Schedule animations and visual updates using requestAnimationFrame to align with the browser’s rendering cycle.
  5. Apply will-change Sparingly:

    • Use the will-change property for elements that change frequently (e.g., transforms or opacity) to optimize performance, but apply it judiciously to avoid memory overhead.
  6. Avoid Layout Thrashing:

    • Separate DOM reads (e.g., offsetHeight) from writes (e.g., style) to prevent multiple recalculations of layout.
  7. Debounce or Throttle Events:

    • Use debounce or throttle techniques for frequent events like scroll and resize to reduce the frequency of updates.

Why It Matters in Interviews

  • Performance Expertise: Demonstrates understanding of critical browser rendering processes.
  • Problem-Solving Skills: Shows the ability to optimize applications for better responsiveness.
  • Real-World Relevance: Highlights practical knowledge of improving user experience, especially in complex or high-performance applications.

Bonus Insights

  • Use Hardware Acceleration:
    • Leverage GPU-accelerated properties like transform and opacity for smoother animations.
  • Measure Performance:
    • Use browser tools like Chrome DevTools’ Performance tab to identify and debug reflow/repaint issues.
  • Avoid Frequent DOM Access:
    • Cache DOM references to minimize repeated queries and computations.

Explore techniques for reducing reflows and repaints on GreatFrontEnd

19. What Are Some Tools That Can Be Used to Measure and Analyze JavaScript Performance?

Measuring and analyzing JavaScript performance is essential for building efficient, responsive web applications. Several tools are available to identify bottlenecks and optimize performance.

Popular Tools for JavaScript Performance Analysis

  1. Chrome DevTools:

    • The Performance panel in Chrome DevTools allows you to profile JavaScript execution, measure load times, and analyze CPU usage.
    • Identify long-running scripts and opportunities for optimization.
  2. Lighthouse:

    • Provides detailed performance audits, including JavaScript execution time, render blocking scripts, and opportunities for improvement.
    • Integrated into Chrome DevTools and also available as a standalone tool.
  3. WebPageTest:

    • A web-based tool that provides in-depth performance testing with metrics like time to first byte (TTFB) and JavaScript load impact.
    • Useful for testing performance under various network conditions.
  4. JSPerf:

    • A benchmarking tool for comparing the performance of different JavaScript code snippets.
    • Helps identify the fastest implementation for specific tasks.
  5. Firefox Developer Tools:

    • Similar to Chrome DevTools, Firefox offers robust profiling tools to analyze JavaScript performance and identify blocking scripts.
  6. Node.js Performance Hooks (for backend JavaScript):

    • Provides utilities to measure and analyze performance in Node.js applications.

Why It Matters in Interviews

  • Optimization Skills: Demonstrates knowledge of performance measurement and the ability to identify and address bottlenecks.
  • Practical Knowledge: Highlights proficiency with industry-standard tools used in modern web development.
  • Debugging Expertise: Shows the ability to diagnose and solve complex performance issues.

Bonus Insights

  • Real-World Relevance:
    • Tools like Lighthouse and WebPageTest are critical for ensuring fast and reliable user experiences, especially for mobile-first applications.
  • Continuous Monitoring:
    • Integrate performance monitoring into CI/CD pipelines using tools like Lighthouse CI or WebPageTest automation.
  • Best Practices:
    • Use profiling data to prioritize optimizations, focusing on critical metrics like time to interactive (TTI) and first contentful paint (FCP).

Explore tools to measure and analyze JavaScript performance on GreatFrontEnd

20. What Are Web Workers and How Can They Be Used to Improve Performance?

Web Workers allow JavaScript code to run in the background, separate from the main thread of a web application. By offloading intensive computations to a worker thread, Web Workers ensure the user interface remains responsive and smooth.

Using Web Workers

  1. Creating a Web Worker:

    • Use the Worker constructor to create a new worker and specify a script file for the worker to execute.
    const worker = new Worker('worker.js');
    
  2. Communication:

    • Main thread and worker communicate using postMessage and onmessage methods.
    • Example:
    // Main thread
    worker.postMessage('Hello, Worker!');
    
    worker.onmessage = (event) => {
        console.log('Message from Worker:', event.data);
    };
    
    // Worker (worker.js)
    onmessage = (event) => {
        const result = `Received: ${event.data}`;
        postMessage(result);
    };
    
  3. Terminating a Worker:

    • Use worker.terminate() to stop the worker when it's no longer needed.

Advantages of Web Workers

  • Improved Performance:
    • Offload heavy computations like data processing, encoding, or image manipulation.
  • Non-Blocking UI:
    • Keep the main thread free to handle user interactions, ensuring a smoother experience.
  • Parallel Processing:
    • Execute multiple tasks concurrently for faster results.

Limitations

  • No DOM Access:
    • Web Workers cannot interact directly with the DOM.
  • Resource Intensive:
    • Workers consume additional memory and processing power.
  • Cross-Origin Restrictions:
    • Workers must follow the same-origin policy for their scripts.

Why It Matters in Interviews

  • Performance Optimization: Demonstrates ability to keep applications responsive during heavy operations.
  • Concurrency Concepts: Shows understanding of JavaScript’s event loop and threading model.
  • Real-World Applications: Highlights practical skills for handling tasks like data processing, real-time updates, or large computations.

Bonus Insights

  • Use Cases:
    • Examples include background data processing, file compression, cryptography, or computationally intensive tasks like video encoding.
  • Best Practices:
    • Avoid overusing workers to prevent excessive resource consumption.
    • Use transferable objects (e.g., ArrayBuffer) for efficient data transfer between threads.
  • Modern Alternatives:
    • Explore tools like Comlink to simplify Web Worker communication.

Explore what Web Workers are and how they can be used to improve performance on GreatFrontEnd

Conclusion

Getting ready to tackle these questions in an interview can set you apart from the competition. It's more than just memorizing answers—it's about grasping the core concepts and confidently applying them to real-world challenges. By mastering these advanced JavaScript topics, you'll not only shine in technical interviews but also gain the skills to create scalable and high-performing web applications.

👉 Looking for a clear and effective strategy to conquer your frontend interviews? Visit GreatFrontEnd for expertly crafted resources! 🌟 Let’s elevate your coding journey together! 💡

Top comments (1)

Collapse
 
makscraft profile image
Maksim Zaikov

Very useful, thank you so much!