Practice Questions

1. What is the purpose of the name attribute on an HTML <input> element? What happens if you omit it from a form field?

Solution

The name attribute identifies the input field when form data is submitted. Each input’s name becomes the key in the key-value pairs sent to the server (e.g., ?email=test@example.com&age=25). If you omit the name attribute, that field’s value is not included in the submitted data at all.

2. Explain what event.preventDefault() does. Write a short example where a button click is handled without the browser performing its default action.

Solution

preventDefault() stops the browser from carrying out its default behavior for an event. For a form submission, the default is to send the data to a server and reload the page. Calling preventDefault() stops that, so you decide what happens instead.

const form = document.querySelector("form");
form.addEventListener("submit", function (event) {
  event.preventDefault();
  console.log("Form submitted without page reload");
});

3. JavaScript’s Date constructor uses 0-indexed months. If a user enters month 3 and year 2026, what Date object should you create to represent that month, and why?

Solution

You should create new Date(2026, 2) because months are 0-indexed in JavaScript: January is 0, February is 1, March is 2, and so on. So you pass month - 1 to the constructor. This means new Date(2026, 2) represents March 1, 2026.

4. Write a regular expression that matches a string containing exactly 5 lowercase letters (a-z). Explain each part of your pattern.

Solution
/^[a-z]{5}$/;
  • ^ – start of string (ensures nothing comes before)
  • [a-z] – any lowercase letter from a to z
  • {5} – exactly 5 of the preceding pattern
  • $ – end of string (ensures nothing comes after)

Example usage:

/^[a-z]{5}$/.test("hello"); // true
/^[a-z]{5}$/.test("Hello"); // false (uppercase H)
/^[a-z]{5}$/.test("hi"); // false (only 2 characters)

5. What is the difference between the test() method and the match() method when working with regular expressions?

Solution

test() is called on a regex and returns a boolean (true or false) indicating whether the string matches the pattern:

/^[0-9]{3}$/.test("123"); // true

match() is called on a string and returns an array of matches (or null if no match). It provides more detail about what was matched:

"123".match(/^[0-9]{3}$/); // ["123"]

Use test() when you only need to know if the input is valid. Use match() when you need to extract matched content from a string.

6. What is an arrow function and how does its syntax differ from a traditional function expression? Show three forms: with multiple parameters, with a single parameter, and with a concise body (implicit return).

Solution

An arrow function is a shorter syntax for writing function expressions, introduced in ES6. It uses => instead of the function keyword.

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

// Arrow function with multiple parameters
const addArrow = (a, b) => {
  return a + b;
};

// Arrow function with a single parameter (parentheses optional)
const double = (x) => {
  return x * 2;
};

// Arrow function with concise body (implicit return, no braces)
const triple = (x) => x * 3;

Differences from traditional functions:

  • Shorter syntax, especially useful as callbacks: arr.map(x => x * 2)
  • When the body is a single expression, you can omit the braces and return keyword (concise body)
  • Arrow functions do not have their own this binding. They inherit this from the enclosing scope

7. Given the array ["5", "3", "8", "1"], use method chaining with map and reduce to convert each element to a number and compute their sum. Write the code using arrow functions.

Solution
const result = ["5", "3", "8", "1"]
  .map((el) => parseInt(el))
  .reduce((acc, val) => acc + val, 0);

console.log(result); // 17

map transforms each string to a number, and reduce accumulates them into a single sum. The second argument to reduce (0) is the initial value of the accumulator.

8. Explain how the reduce method works. What are the two arguments it accepts, and what parameters does the reducer function receive?

Solution

reduce() processes each element of an array to produce a single output value. It accepts two arguments:

  1. A reducer function that is called for each element
  2. An initial value for the accumulator

The reducer function receives:

  • accumulator – the running result from previous iterations (starts as the initial value)
  • currentValue – the current array element being processed
  • currentIndex (optional) – the index of the current element
const nums = [10, 20, 30];
const total = nums.reduce((acc, val) => acc + val, 0);
// Iteration 1: acc=0,  val=10 -> 10
// Iteration 2: acc=10, val=20 -> 30
// Iteration 3: acc=30, val=30 -> 60
console.log(total); // 60

9. Rewrite the following code using arrow functions and method chaining so that it fits on a single statement:

let arr = "abcdef".split("");
arr = arr.reverse();
arr = arr.map(function (ch) {
  return ch.toUpperCase();
});
Solution
const arr = "abcdef"
  .split("")
  .reverse()
  .map((ch) => ch.toUpperCase());

// Result: ["F", "E", "D", "C", "B", "A"]

Method chaining works because each method (split, reverse, map) returns an array, so you can call the next method directly on the result.

10. Write a function isValidPostalCode(code) that returns true if the input is a valid US ZIP code. A valid ZIP code is either exactly 5 digits or 5 digits followed by a hyphen and 4 more digits (e.g., “21218” or “21218-1234”).

Solution
function isValidPostalCode(code) {
  return /^[0-9]{5}(-[0-9]{4})?$/.test(code);
}

isValidPostalCode("21218"); // true
isValidPostalCode("21218-1234"); // true
isValidPostalCode("2121"); // false
isValidPostalCode("21218-12"); // false
isValidPostalCode("abcde"); // false

Breaking down the regex:

  • ^[0-9]{5} – starts with exactly 5 digits
  • (-[0-9]{4})? – optionally followed by a hyphen and 4 digits
  • $ – end of string

11. Why is it good practice to delegate validation logic into separate functions rather than putting all validation code inside a single event handler?

Solution

Delegating validation to separate functions improves code in several ways:

  • Readability: The event handler shows the high-level steps (“check expiry, check CVV, check card number”), and the details are in dedicated functions.
  • Reusability: A validation function like isValid(cardNumber) can be called from multiple places, not just one event handler.
  • Testability: Small, focused functions are easier to test individually. You can verify that isValid("4003600000000014") returns true without simulating a form submission.
  • Maintainability: If the validation logic needs to change, you only update one function rather than searching through a large handler.

12. Consider this reduce call that doubles even-indexed values before summing. Trace through the execution and determine the final result:

const result = [1, 2, 3, 4].reduce((acc, val, idx) => {
  if (idx % 2 === 0) {
    val *= 2;
  }
  return acc + val;
}, 0);
Solution

Tracing each iteration:

  • Index 0: idx % 2 === 0 is true, so val = 1 * 2 = 2. acc = 0 + 2 = 2
  • Index 1: idx % 2 === 0 is false, so val = 2. acc = 2 + 2 = 4
  • Index 2: idx % 2 === 0 is true, so val = 3 * 2 = 6. acc = 4 + 6 = 10
  • Index 3: idx % 2 === 0 is false, so val = 4. acc = 10 + 4 = 14

The final result is 14.

So a reducer can use currentIndex to treat elements differently depending on their position.