10 Vanilla JavaScript Interview Questions and Answers
Prepare for your web development interview with these Vanilla JavaScript questions and answers to enhance your core programming skills.
Prepare for your web development interview with these Vanilla JavaScript questions and answers to enhance your core programming skills.
Vanilla JavaScript, the core language without any libraries or frameworks, remains a fundamental skill for web developers. Its simplicity and versatility make it essential for creating dynamic and interactive web applications. Mastering Vanilla JavaScript provides a strong foundation for understanding more complex frameworks and libraries, making it a critical competency in the ever-evolving tech landscape.
This article offers a curated selection of interview questions designed to test and enhance your understanding of Vanilla JavaScript. By working through these questions, you will gain deeper insights into the language’s core concepts and be better prepared to demonstrate your proficiency in technical interviews.
To reverse a string in JavaScript, you can use built-in methods to split the string into an array of characters, reverse the array, and then join the characters back into a string. This approach is straightforward and efficient.
function reverseString(str) { return str.split('').reverse().join(''); } console.log(reverseString("hello")); // Output: "olleh" console.log(reverseString("JavaScript")); // Output: "tpircSavaJ"
Closures in JavaScript allow a function to access variables from an outer function’s scope even after the outer function has returned. This is useful for data encapsulation and maintaining state.
Example:
function createCounter() { let count = 0; return function() { count += 1; return count; }; } const counter = createCounter(); console.log(counter()); // 1 console.log(counter()); // 2 console.log(counter()); // 3
In this example, the inner function maintains access to the count
variable even after createCounter
has finished executing. Each call to counter
increments and returns the updated count.
Debouncing ensures that a function is not called too frequently, improving performance in scenarios like handling user input events.
Here is a simple implementation of a debounce function:
function debounce(func, wait) { let timeout; return function(...args) { clearTimeout(timeout); timeout = setTimeout(() => func.apply(this, args), wait); }; } // Example usage: const handleResize = () => { console.log('Window resized'); }; window.addEventListener('resize', debounce(handleResize, 300));
The debounce
function takes two arguments: the function to be debounced (func
) and the delay in milliseconds (wait
). It returns a new function that clears any existing timeout and sets a new one, ensuring the original function is only called after the specified delay.
The event loop in JavaScript manages asynchronous operations. JavaScript is single-threaded but can handle multiple operations concurrently through the event loop, allowing for non-blocking I/O operations.
Example:
console.log('Start'); setTimeout(() => { console.log('Timeout'); }, 0); console.log('End');
In this example, Start and End are logged first because the setTimeout callback is placed in the task queue and only executed after the call stack is empty.
Promises in JavaScript handle asynchronous operations, representing a value that may be available now, in the future, or never. They provide a cleaner way to handle asynchronous code compared to traditional callbacks.
Here is a promise-based function that fetches data from an API:
function fetchData(url) { return new Promise((resolve, reject) => { fetch(url) .then(response => { if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); }) .then(data => resolve(data)) .catch(error => reject(error)); }); } // Usage example: fetchData('https://api.example.com/data') .then(data => console.log(data)) .catch(error => console.error('Error:', error));
Flattening a nested array means converting it into a single, one-dimensional array. This can be achieved using recursion or JavaScript’s built-in methods.
Here is an example using recursion:
function flattenArray(arr) { let result = []; arr.forEach(element => { if (Array.isArray(element)) { result = result.concat(flattenArray(element)); } else { result.push(element); } }); return result; } const nestedArray = [1, [2, [3, 4], 5], 6]; console.log(flattenArray(nestedArray)); // Output: [1, 2, 3, 4, 5, 6]
The module pattern in JavaScript creates private and public encapsulation within a single object, helping organize code and avoid global namespace pollution. An IIFE (Immediately Invoked Function Expression) is a function that runs as soon as it is defined.
Example:
var myModule = (function() { // Private variables and functions var privateVar = 'I am private'; function privateMethod() { console.log(privateVar); } // Public API return { publicMethod: function() { privateMethod(); } }; })(); myModule.publicMethod(); // Outputs: I am private
In this example, myModule
is an IIFE that returns an object containing a public method publicMethod
. The private variable privateVar
and the private function privateMethod
are not accessible from outside the module.
Deep cloning an object means creating a new object that is a complete copy of the original, including all nested objects and arrays. This is different from shallow cloning, which only copies the top-level properties.
Here is a function that performs a deep clone:
function deepClone(obj) { if (obj === null || typeof obj !== 'object') { return obj; } if (Array.isArray(obj)) { const arrCopy = []; for (let i = 0; i < obj.length; i++) { arrCopy[i] = deepClone(obj[i]); } return arrCopy; } const objCopy = {}; for (const key in obj) { if (obj.hasOwnProperty(key)) { objCopy[key] = deepClone(obj[key]); } } return objCopy; } const original = { a: 1, b: { c: 2, d: [3, 4] } }; const cloned = deepClone(original); console.log(cloned);
Event delegation involves adding an event listener to a parent element to manage events for its child elements. This technique reduces the number of event listeners needed.
Example:
document.getElementById('parent').addEventListener('click', function(event) { if (event.target && event.target.matches('button.child')) { console.log('Button clicked:', event.target.textContent); } }); // HTML structure // <div id="parent"> // <button class="child">Button 1</button> // <button class="child">Button 2</button> // </div>
In this example, an event listener is added to the parent element with the id “parent”. The event listener checks if the clicked element matches the selector button.child
.
map
, filter
, or reduce
to manipulate an array.To manipulate an array using map
, filter
, or reduce
, you can transform, filter, or aggregate the elements of the array. Here is an example demonstrating the use of all three functions:
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // Use map to create a new array with each element squared const squaredNumbers = numbers.map(num => num * num); // Use filter to create a new array with only even numbers const evenNumbers = numbers.filter(num => num % 2 === 0); // Use reduce to calculate the sum of all elements in the array const sumOfNumbers = numbers.reduce((acc, num) => acc + num, 0); console.log(squaredNumbers); // [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] console.log(evenNumbers); // [2, 4, 6, 8, 10] console.log(sumOfNumbers); // 55