50 Advanced Vanilla JavaScript Questions with Detailed Explanations
JavaScript Developer WorldWide
Join the JavaScript Developers worldwide JavaScript Developers JavaScript Coders JavaScript Freelancers
Download https://basescripts.com/50-advanced-vanilla-javascript-questions-with-detailed-explanations
JavaScript is a versatile language with many nuances and advanced features. In this post, you’ll find 50 new questions covering topics from global objects and module loaders to service workers and job queues. Each entry includes a clear explanation and practical code examples.
1. What is the difference between the global object in a browser (window) and in Node.js (global), and how does this affect code portability?
Answer: In browsers, the global object is window (or self in Web Workers), while in Node.js it’s global. Code relying on browser globals (e.g., window.document) won’t run in Node.js, and vice versa.
Explanation: Developers must write environment-agnostic code or use conditionals (or libraries like UMD) to bridge the differences.
Example:
// Environment agnostic global object:
const root = typeof window !== 'undefined' ? window : global;
root.myGlobalVar = "Hello, world!";
2. How can you implement a module loader without using ES modules or bundlers (e.g., a simple script-based dependency loader)?
Answer: You can create a module loader by defining a registry to store modules and a require function that retrieves them. Each module can be defined with a function that returns its exports.
Explanation: This approach mimics CommonJS. It helps in managing dependencies in environments where ES modules aren’t available.
Example:
const moduleRegistry = {};
function define(moduleName, dependencies, factory) {
??moduleRegistry[moduleName] = { dependencies, factory, exports: {} };
}
function require(moduleName) {
??const module = moduleRegistry[moduleName];
??if (!module.instance) {
????const args = module.dependencies.map(require);
????module.instance = module.factory.apply(null, args);
??}
??return module.instance;
}
// Define modules:
define('math', [], function() {
??return {
????add: (a, b) => a + b,
??};
});
define('app', ['math'], function(math) {
??console.log("3 + 4 =", math.add(3, 4));
});
// Load the main module:
require('app');
3. What are some ways to measure and optimize JavaScript performance in the browser?
Answer: Use the Performance API (e.g., performance.now(), performance.mark(), and performance.measure()) along with browser developer tools (like Chrome’s Timeline) for profiling.
Explanation: Measuring performance helps in identifying bottlenecks. Tools such as the Performance panel, Lighthouse audits, and code instrumentation are invaluable.
Example:
performance.mark('start');
// Code to measure
for (let i = 0; i < 1000000; i++) { /* heavy computation */ }
performance.mark('end');
performance.measure('Loop Duration', 'start', 'end');
const measures = performance.getEntriesByName('Loop Duration');
console.log(measures[0].duration, 'ms');
4. Explain the concept of “run-to-completion” in JavaScript and how it influences concurrency.
Answer: JavaScript is single-threaded and follows a run-to-completion model. Once a function starts executing, it runs until it completes, blocking other operations in the meantime.
Explanation: This model prevents race conditions but means long-running tasks block the main thread. Asynchronous patterns help avoid UI freezes.
Example:
console.log("Task started");
// A long-running synchronous loop:
for (let i = 0; i < 1e9; i++) {}
console.log("Task completed");
5. How do you manage error handling across multiple asynchronous operations without relying on Promises or async/await (e.g., callback patterns)?
Answer: You can use error-first callback patterns where the callback’s first parameter is an error object. Each asynchronous function checks for an error before proceeding.
Explanation: This pattern is common in Node.js. It requires careful nesting or using helper libraries to avoid “callback hell.”
Example:
function asyncOperation(callback) {
??setTimeout(() => {
????// Simulate error-free operation:
????callback(null, "Result");
??}, 500);
}
asyncOperation((err, result) => {
??if (err) {
????console.error("Error:", err);
??} else {
????console.log("Success:", result);
??}
});
6. What is the difference between document.readyState values (loading, interactive, complete), and how does it compare to DOMContentLoaded vs. load events?
Answer:
Explanation: DOMContentLoaded fires when the DOM is ready, while the load event fires when all resources are loaded. Checking document.readyState can be used to determine the current loading phase.
Example:
if (document.readyState === "complete") {
??console.log("Page is fully loaded");
} else {
??window.addEventListener("load", () => {
????console.log("Page load event fired");
??});
}
7. How would you detect and handle different rendering engines (e.g., Blink, WebKit, Gecko) purely with vanilla JavaScript (without libraries)?
Answer: You can inspect the navigator.userAgent string or use feature detection for unique engine properties.
Explanation: Feature detection is preferred over user agent sniffing, but sometimes it’s necessary for specific rendering engine workarounds.
Example:
const ua = navigator.userAgent;
if (/Gecko\/\d/.test(ua) && !/like Gecko/.test(ua)) {
??console.log("Using Gecko engine");
} else if (/AppleWebKit\/\d+/.test(ua)) {
??console.log("Using WebKit/Blink engine");
}
8. What are “accessor properties” (get and set) in object literals, and how do they differ from data properties?
Answer: Accessor properties use getter and setter functions to control property access, while data properties simply store values.
Explanation: Accessors allow you to compute values dynamically or validate data upon assignment.
Example:
const person = {
??firstName: "John",
??lastName: "Doe",
??get fullName() {
????return ${this.firstName} ${this.lastName};
??},
??set fullName(name) {
????const parts = name.split(" ");
????if (parts.length >= 2) {
??????this.firstName = parts[0];
??????this.lastName = parts[1];
????}
??}
};
console.log(person.fullName); // "John Doe"
person.fullName = "Jane Smith";
console.log(person.firstName, person.lastName); // "Jane" "Smith"
9. Describe a scenario where you might prefer using a Map or Set over a plain object or array, and explain why.
Answer: Map and Set provide better performance for frequent additions and deletions, and Map allows keys of any type while Set ensures unique values.
Explanation: They offer more predictable iteration order and built-in methods for common operations.
Example:
// Using a Map:
const userRoles = new Map();
userRoles.set("Alice", "admin");
userRoles.set("Bob", "editor");
console.log(userRoles.get("Alice")); // "admin"
// Using a Set:
const uniqueIds = new Set([1, 2, 3]);
uniqueIds.add(2); // Duplicate not added
console.log(uniqueIds.size); // 3
10. Explain how with works in JavaScript and why it’s generally discouraged.
Answer: The with statement extends the scope chain for a statement, allowing you to reference object properties without repeatedly specifying the object name.
Explanation: It’s discouraged because it makes code ambiguous, can lead to unexpected behaviors, and hinders optimization.
Example:
const obj = { a: 1, b: 2 };
with (obj) {
??// a and b are available directly.
??console.log(a + b);
}
// Better: directly reference obj.a and obj.b
11. How would you create a small vanilla JavaScript utility to handle client-side routing (a single-page app approach) without external frameworks?
Answer: You can use the History API (pushState, popstate event) to manage URL changes and update the view based on the current path.
Explanation: A simple router listens for changes in URL and then renders content accordingly.
Example:
function render(route) {
??const content = document.getElementById("content");
??content.innerHTML = <h2>You are at: ${route}</h2>;
}
window.addEventListener("popstate", () => {
??render(location.pathname);
});
// Navigation function:
function navigate(route) {
??history.pushState({}, "", route);
??render(route);
}
// Initial render:
render(location.pathname);
// Example usage:
// <button onclick="navigate('/about')">About</button>
12. What is the difference between using for...in and Object.keys() (or Object.entries()) when iterating over an object’s properties?
Answer:
Explanation: Using Object.keys() or Object.entries() helps avoid unintentional iteration over prototype properties.
Example:
const obj = { a: 1, b: 2 };
for (let key in obj) {
??console.log(key); // May include inherited properties
}
Object.keys(obj).forEach(key => console.log(key)); // "a", "b"
13. How do you detect and respond to changes in network connectivity (online/offline) with vanilla JavaScript?
Answer: You can listen for the online and offline events on the window and check the navigator.onLine property.
Explanation: These events allow you to adapt your application’s behavior when the network status changes.
Example:
window.addEventListener("online", () => console.log("Network connected"));
window.addEventListener("offline", () => console.log("Network disconnected"));
console.log("Online status:", navigator.onLine);
14. What are some approaches to preventing script-injection (XSS) attacks in vanilla JavaScript?
Answer: Common approaches include:
Explanation: Always sanitize and validate external input to prevent injection of malicious scripts.
Example:
function sanitize(input) {
??const div = document.createElement("div");
??div.textContent = input;
??return div.innerHTML;
}
const userInput = "<script>alert('XSS')</script>";
document.getElementById("output").innerHTML = sanitize(userInput);
15. How would you implement lazy-loading of images purely with JavaScript and the Intersection Observer API?
Answer: Use the Intersection Observer to detect when an image enters the viewport, then replace its placeholder source with the actual image URL.
Explanation: This improves performance by loading images only when needed.
Example:
const images = document.querySelectorAll("img[data-src]");
const observer = new IntersectionObserver(entries => {
??entries.forEach(entry => {
????if (entry.isIntersecting) {
??????const img = entry.target;
??????img.src = img.getAttribute("data-src");
??????img.removeAttribute("data-src");
??????observer.unobserve(img);
????}
??});
});
images.forEach(img => observer.observe(img));
16. Explain how to create a custom JSON parser that can handle comments or trailing commas.
Answer: You can pre-process the JSON string to remove comments (using regex) or trailing commas before passing it to JSON.parse().
Explanation: Since standard JSON doesn’t support these features, you can sanitize the string to conform to JSON syntax.
Example:
function parseCustomJSON(str) {
??// Remove comments (simple regex for // comments)
??const withoutComments = str.replace(/\/\/.*$/gm, '');
??// Remove trailing commas:
??const cleaned = withoutComments.replace(/,\s*([\]}])/g, '$1');
??return JSON.parse(cleaned);
}
const jsonString = `
{
??// This is a comment
??"name": "Alice",
??"age": 30, // trailing comma
}
`;
console.log(parseCustomJSON(jsonString));
17. What are some pitfalls of using bitwise operators (e.g., |, amp;, ^) in JavaScript?
Answer: Bitwise operators convert operands to 32-bit signed integers, which can lead to unexpected behavior with large numbers or floating-point values.
Explanation: Be cautious with values beyond the 32-bit integer range; unexpected sign changes or truncation might occur.
Example:
console.log(4294967296 | 0); // 0 because 2^32 becomes 0 in 32-bit
18. How can you polyfill or shim new JavaScript features for older browsers without relying on external libraries?
Answer: You can write conditional code that checks if a feature exists and, if not, defines it using older JavaScript constructs.
Explanation: This ensures compatibility without loading large libraries. Many polyfills follow this pattern.
Example:
if (!Array.prototype.includes) {
??Array.prototype.includes = function(searchElement, fromIndex) {
????return this.indexOf(searchElement, fromIndex) !== -1;
??};
}
19. What is the difference between Function.prototype.call(), Function.prototype.apply(), and using the spread operator for argument handling?
Answer:
Explanation: They achieve similar results but offer flexibility depending on how you have your arguments structured.
Example:
function sum(a, b) {
??return a + b;
}
console.log(sum.call(null, 2, 3)); // 5
console.log(sum.apply(null, [2, 3])); // 5
const args = [2, 3];
console.log(sum(...args)); // 5
20. How do you handle big integers in JavaScript (beyond the 53-bit integer limit) using only built-in features?
Answer: JavaScript now includes the BigInt type to represent integers beyond the safe limit for numbers.
Explanation: BigInt enables safe arithmetic on very large integers, though it cannot be mixed directly with regular numbers.
Example:
const bigNumber = BigInt("9007199254740993"); // 2^53 + 1
console.log(bigNumber + 2n); // BigInt arithmetic requires the "n" suffix
21. Explain how you would implement a small templating function in vanilla JavaScript (e.g., replacing placeholders in a string).
Answer: You can create a function that uses regular expressions to replace placeholders with values from an object.
Explanation: This allows you to create dynamic strings for simple templating without external libraries.
Example:
function template(str, data) {
??return str.replace(/\{\{(\w+)\}\}/g, (match, key) => data[key] || '');
}
const tmpl = "Hello, {{name}}! You have {{count}} new messages.";
console.log(template(tmpl, { name: "Alice", count: 5 }));
22. What is a “generator function,” and how might you use generators to manage asynchronous flows without async/await or promises?
Answer: A generator function (declared with function*) can yield multiple values and pause/resume execution. It can be combined with a runner to step through asynchronous operations in a synchronous-like manner.
Explanation: Generators allow you to write asynchronous code that appears synchronous by yielding control until a value is ready.
Example:
function* asyncFlow() {
??const result = yield new Promise(resolve => setTimeout(() => resolve("Done"), 500));
??console.log(result);
}
// A simple runner:
function run(generator) {
??const it = generator();
??function step(nextF) {
????const next = nextF();
????if (next.done) return;
????next.value.then(result => step(() => it.next(result)));
??}
??step(() => it.next());
}
run(asyncFlow);
23. How can you build a minimal testing framework in vanilla JavaScript that runs in the browser (without external libraries)?
Answer: You can create a framework that accepts test cases as functions, executes them, and reports the results to the DOM or console.
Explanation: A simple framework can include functions to assert conditions and count passed/failed tests.
Example:
const tests = [];
function test(name, fn) {
??tests.push({ name, fn });
}
function runTests() {
??let passed = 0;
??tests.forEach(({ name, fn }) => {
????try {
??????fn();
??????console.log(`? ${name}`);
??????passed++;
????} catch (error) {
??????console.error(`? ${name}:`, error);
????}
??});
??console.log(`Passed ${passed}/${tests.length} tests`);
}
// Example test:
test("Addition works", () => {
??if (2 + 2 !== 4) throw new Error("2 + 2 should equal 4");
});
runTests();
24. Describe how to implement client-side data caching using the Cache Storage API or localStorage.
Answer: You can store API responses or static assets in localStorage for simple caching or use the Cache Storage API in service workers for more granular control.
Explanation: The Cache Storage API offers more advanced control over request/response caching, while localStorage is simpler but synchronous.
Example (localStorage):
function cacheData(key, data) {
??localStorage.setItem(key, JSON.stringify(data));
}
function getCachedData(key) {
??const data = localStorage.getItem(key);
??return data ? JSON.parse(data) : null;
}
cacheData("user", { name: "Alice" });
console.log(getCachedData("user"));
25. What are some ways to detect memory leaks in a large vanilla JavaScript application, and how might you fix them?
Answer: Use browser developer tools (like Chrome DevTools’ Memory panel) to take heap snapshots and analyze retained objects. Common fixes include clearing timers, removing event listeners, and ensuring closures do not retain unnecessary references.
Explanation: Regular profiling helps identify leaks. Review code for unintended global variables and detached DOM nodes.
Example:
// Make sure to remove intervals when not needed:
const intervalId = setInterval(() => console.log("Tick"), 1000);
// Later...
clearInterval(intervalId);
26. How can you manually implement the new operator’s behavior using a factory function or an object creation pattern?
Answer: You can simulate new by creating a new object, setting its prototype, and applying the constructor function.
Explanation: This manual approach reveals what the new operator does under the hood.
Example:
function myNew(constructor, ...args) {
??const obj = Object.create(constructor.prototype);
??const result = constructor.apply(obj, args);
??return result instanceof Object ? result : obj;
}
function Person(name) {
??this.name = name;
}
const person = myNew(Person, "Alice");
console.log(person.name); // "Alice"
27. What is the difference between “named exports” and “default exports” in ES modules, and how can you import them differently?
Answer: Named exports allow exporting multiple items from a module, and they must be imported with the exact same name. Default exports export a single value and can be imported with any name.
Explanation: Understanding the difference is key for code organization in modern JavaScript projects.
Example (module file):
// math.js
export function add(a, b) { return a + b; }
export default function subtract(a, b) { return a - b; }
// importing file:
import subtract, { add } from './math.js';
console.log(add(5, 2));? ? ? ? // 7
console.log(subtract(5, 2)); ? // 3
28. Explain the concept of a “thunk” in JavaScript, and how it might be used to defer computation or handle asynchronous code.
Answer: A thunk is a function with no arguments that wraps a computation or an expression. It defers evaluation until called.
Explanation: Thunks can simplify asynchronous flows by delaying computation until needed.
Example:
function createThunk(fn, ...args) {
??return function() {
????return fn(...args);
??};
}
const thunk = createThunk((a, b) => a + b, 2, 3);
console.log(thunk()); // 5
29. How do you handle internationalization (i18n) and localization (l10n) purely in vanilla JavaScript (e.g., using the Intl API)?
Answer: The Intl API provides built-in methods for formatting dates, numbers, and currencies according to locale. You can also build a simple dictionary-based system for translating text.
Explanation: Using Intl ensures proper locale-specific formatting.
Example:
const number = 1234567.89;
const formatted = new Intl.NumberFormat('de-DE').format(number);
console.log(formatted); // "1.234.567,89"
30. What are some methods to measure script download and execution times in a browser environment purely with vanilla JS?
Answer: You can use the Performance API (e.g., performance.timing) to measure download and execution times.
Explanation: These measurements help in diagnosing performance bottlenecks in resource loading.
Example:
window.addEventListener("load", () => {
??const timing = performance.timing;
??console.log("Time to load:", timing.loadEventEnd - timing.navigationStart, "ms");
});
31. How do you implement a plugin architecture (like jQuery plugins) purely with vanilla JavaScript?
Answer: You can extend native prototypes (like HTMLElement.prototype) or attach methods to a global object to enable plugin functionality.
Explanation: A plugin architecture allows for extensible features without altering the core library.
Example:
// Add a plugin method to all elements:
HTMLElement.prototype.highlight = function(color = "yellow") {
??this.style.backgroundColor = color;
};
// Usage:
document.getElementById("myElement").highlight("lightblue");
32. Explain how you might implement “function overloading” in JavaScript, given that the language doesn’t have built-in overloading.
Answer: Function overloading can be simulated by checking argument types or lengths within a single function and branching logic accordingly.
Explanation: This manual method allows a function to behave differently based on its inputs.
Example:
function doSomething() {
??if (arguments.length === 1) {
????console.log("One argument:", arguments[0]);
??} else if (arguments.length === 2) {
????console.log("Two arguments:", arguments[0], arguments[1]);
??}
}
doSomething("Test");
doSomething("Hello", "World");
33. What is a “service worker,” and how would you register and control it in pure JavaScript for offline functionality?
Answer: A service worker is a background script that intercepts network requests to enable offline caching and push notifications. Registration is done via navigator.serviceWorker.register().
Explanation: Service workers improve reliability and performance by caching resources.
Example:
if ('serviceWorker' in navigator) {
??navigator.serviceWorker.register('/service-worker.js')
????.then(reg => console.log('Service Worker registered', reg))
????.catch(err => console.error('Registration failed:', err));
}
34. How do you create a dynamic script loader function to load external scripts asynchronously without blocking the main thread?
Answer: You can create a function that creates a <script> element, sets its src, and appends it to the DOM.
Explanation: This method allows dynamic loading of scripts without blocking the initial page rendering.
Example:
function loadScript(url, callback) {
??const script = document.createElement("script");
??script.src = url;
??script.async = true;
??script.onload = () => callback(null, url);
??script.onerror = () => callback(new Error(`Failed to load ${url}`));
??document.head.appendChild(script);
}
loadScript("https://example.com/script.js", (err, url) => {
??if (err) console.error(err);
??else console.log(`${url} loaded successfully`);
});
35. What are “optional chaining” (?.) and “nullish coalescing” (??), and how might you polyfill them for older browsers?
Answer:
Explanation: Polyfilling these features is complex, so in older browsers you might use conditional checks instead.
Example (without polyfill):
const user = { address: { city: "Wonderland" } };
console.log(user?.address?.city); // "Wonderland"
console.log(user.name ?? "Anonymous"); // "Anonymous"
36. Describe how you would implement a very basic drag-and-drop feature using only the DOM Drag and Drop API.
Answer: Attach event listeners (dragstart, dragover, drop) to elements. Prevent default behavior in dragover to allow dropping.
Explanation: This API provides native events to handle drag-and-drop interactions.
Example:
// HTML elements should have draggable="true" where needed.
const draggable = document.getElementById("draggable");
draggable.addEventListener("dragstart", e => {
??e.dataTransfer.setData("text/plain", e.target.id);
});
const dropZone = document.getElementById("dropZone");
dropZone.addEventListener("dragover", e => e.preventDefault());
dropZone.addEventListener("drop", e => {
??e.preventDefault();
??const id = e.dataTransfer.getData("text/plain");
??const element = document.getElementById(id);
??dropZone.appendChild(element);
});
37. How do you handle cross-domain requests with vanilla JavaScript (e.g., using CORS headers, JSONP, or other techniques)?
Answer: For modern browsers, use the Fetch API with proper CORS headers on the server. JSONP is an older technique that involves loading a script with a callback.
Explanation: CORS is the standard method, while JSONP is only used when CORS isn’t available.
Example (Fetch with CORS):
fetch("https://api.example.com/data", { mode: "cors" })
??.then(response => response.json())
??.then(data => console.log(data))
??.catch(err => console.error(err));
38. What is the difference between “host objects” and “native objects” in JavaScript, and how has this distinction changed over time?
Answer: Native objects are provided by the ECMAScript specification (like Array, Object), while host objects are provided by the runtime environment (like window in browsers). Modern JavaScript engines have blurred these distinctions as host objects behave more like native objects.
Explanation: Understanding this helps when dealing with cross-environment compatibility issues.
Example:
// In browsers, window is a host object, but it can be iterated similarly to native objects.
console.log(typeof window); // "object"
39. Explain how you can manually handle date and time manipulations without using external libraries like Moment.js or date-fns.
Answer: Use the built-in Date object along with its methods (getTime(), getFullYear(), etc.) to manipulate dates.
Explanation: While verbose, native methods allow you to compute differences, format dates, and perform arithmetic.
Example:
const now = new Date();
const tomorrow = new Date(now.getTime() + 24 60 60 * 1000);
console.log(tomorrow.toISOString());
40. How can you dynamically create and dispatch custom events in vanilla JavaScript (e.g., using new CustomEvent) and listen for them?
Answer: Use CustomEvent to create events with additional data, and dispatch them on DOM elements. Add event listeners to capture these events.
Explanation: This pattern allows decoupled communication between components.
Example:
const event = new CustomEvent("myEvent", { detail: { message: "Hello" } });
document.addEventListener("myEvent", e => console.log(e.detail.message));
document.dispatchEvent(event);
41. What are “static” class fields and methods in ES6+ classes, and how do they differ from instance fields/methods?
Answer: Static fields and methods belong to the class itself rather than any instance, meaning they are accessed on the class rather than an object instance.
Explanation: They’re useful for utility functions or data that applies to the class as a whole.
Example:
class MathUtil {
??static add(a, b) {
????return a + b;
??}
}
console.log(MathUtil.add(5, 3)); // 8
42. Describe how to implement a minimal data-binding system (model-view synchronization) in plain JavaScript.
Answer: You can set up an observer pattern where changes to a model trigger callbacks that update the view. This often involves getters/setters or Proxy objects.
Explanation: A simple data-binding system updates DOM elements when model properties change.
Example:
const model = { text: "Hello" };
const view = document.getElementById("output");
// Simple binding function:
function bind() {
??view.textContent = model.text;
}
// Update model and view:
model.text = "Hello, World!";
bind();
43. How do you handle real-time updates in a web application using long polling or Server-Sent Events (SSE) without any frameworks?
Answer: For SSE, create an EventSource that listens for messages from the server. For long polling, repeatedly make AJAX requests once each request completes.
Explanation: These techniques keep the client updated with minimal delay.
Example (SSE):
if (window.EventSource) {
??const source = new EventSource("/sse-endpoint");
??source.onmessage = event => {
????console.log("New message:", event.data);
??};
}
44. Explain the nuances of Array.prototype.sort() in JavaScript, especially with numeric sorting and Unicode strings.
Answer: By default, .sort() converts elements to strings, which can lead to incorrect ordering for numbers. A compare function is needed for proper numeric sorting. Unicode sorting may require localeCompare.
Explanation: Providing a compare function ensures accurate and expected ordering.
Example:
const numbers = [10, 2, 5];
numbers.sort((a, b) => a - b);
console.log(numbers); // [2, 5, 10]
const strings = ["?", "z", "a"];
strings.sort((a, b) => a.localeCompare(b));
console.log(strings); // Sorted correctly based on locale
45. What are the pros and cons of using the innerHTML property vs. textContent or DOM manipulation methods like appendChild()?
Answer:
Explanation: Choose based on context, security needs, and performance requirements.
Example:
// Safer text insertion:
document.getElementById("output").textContent = "<p>This is plain text</p>";
46. How would you create a custom ESLint or JSHint rule to enforce specific coding conventions in a vanilla JavaScript codebase?
Answer: Custom rules are defined as functions that traverse the Abstract Syntax Tree (AST) and report violations. ESLint provides an API for writing such rules.
Explanation: Writing custom rules helps maintain consistent code style across a project.
Example (conceptual):
// A simplified ESLint rule structure:
module.exports = {
??meta: { type: "suggestion" },
??create: function(context) {
????return {
??????Identifier(node) {
????????if (node.name === "foo") {
??????????context.report(node, "Avoid using 'foo' as an identifier.");
????????}
??????}
????};
??}
};
47. How can you detect the user’s preferred color scheme (light or dark) using vanilla JavaScript and apply conditional styles?
Answer: Use the window.matchMedia() method to detect if the user’s OS prefers a dark color scheme.
Explanation: This allows you to dynamically adjust themes based on user preferences.
Example:
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
??document.body.classList.add("dark-mode");
} else {
??document.body.classList.add("light-mode");
}
48. What is the difference between synchronous iteration (for...of) and asynchronous iteration (for await...of) in vanilla JS?
Answer: for...of iterates over synchronous iterables (like arrays), while for await...of is designed for asynchronous iterators (like streams or async generators) that return promises.
Explanation: for await...of waits for each promise to resolve before continuing, which is crucial for asynchronous data flows.
Example (Async Iterator):
async function* asyncGenerator() {
??yield "Hello";
??yield "World";
}
(async () => {
??for await (const word of asyncGenerator()) {
????console.log(word);
??}
})();
49. How do you perform advanced image manipulation (like resizing or cropping) purely in vanilla JavaScript using lt;canvasgt;?
Answer: You can load an image onto a <canvas>, then use canvas methods (drawImage(), etc.) to resize, crop, or otherwise manipulate the image data.
Explanation: The Canvas API provides pixel-level control over images.
Example:
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");
const img = new Image();
img.src = "path/to/image.jpg";
img.onload = () => {
??// Crop the image: source x, y, width, height, destination x, y, width, height
??ctx.drawImage(img, 50, 50, 200, 200, 0, 0, 200, 200);
};
50. Explain how you might implement a job queue or task scheduler in vanilla JavaScript that handles tasks sequentially.
Answer: You can create a job queue using an array and process each task sequentially using setTimeout or promises to ensure one task completes before starting the next.
Explanation: This pattern is useful for managing a series of asynchronous operations that must run in order.
Example:
class TaskQueue {
??constructor() {
????this.queue = [];
????this.running = false;
??}
??add(task) {
????this.queue.push(task);
????this.runNext();
??}
??runNext() {
????if (this.running || !this.queue.length) return;
????this.running = true;
????const task = this.queue.shift();
????task().then(() => {
??????this.running = false;
??????this.runNext();
????});
??}
}
// Usage:
const queue = new TaskQueue();
queue.add(() => new Promise(resolve => {
??console.log("Task 1");
??setTimeout(resolve, 1000);
}));
queue.add(() => new Promise(resolve => {
??console.log("Task 2");
??setTimeout(resolve, 1000);
}));
These 50 questions, complete with detailed answers, explanations, and examples, cover a broad spectrum of advanced topics in vanilla JavaScript. They’re designed to challenge your understanding and help you build robust, modern web applications.