Chapter 25 Advanced 50 Questions

Practice Questions — Project: Build an Interactive Portfolio Website

← Back to Notes
8 Easy
11 Medium
8 Hard

Topic-Specific Questions

Question 1
Easy
What is the output?
const el = document.querySelector('#hero');
el.scrollIntoView({ behavior: 'smooth' });
console.log('Scrolling started');
Does scrollIntoView block execution?
Scrolling started (prints immediately, scroll happens asynchronously)
Question 2
Easy
What is the output?
const btn = document.createElement('button');
btn.dataset.category = 'javascript';
console.log(btn.dataset.category);
console.log(btn.getAttribute('data-category'));
dataset and data-* attributes are two ways to access the same thing.
javascript
javascript
Question 3
Easy
What is the output?
document.body.classList.add('light-mode');
console.log(document.body.classList.contains('light-mode'));
document.body.classList.toggle('light-mode');
console.log(document.body.classList.contains('light-mode'));
add adds the class, toggle removes it if present.
true
false
Question 4
Medium
What is the output?
const projects = [
  { title: 'A', category: 'web' },
  { title: 'B', category: 'js' },
  { title: 'C', category: 'web' },
  { title: 'D', category: 'design' }
];
const webProjects = projects.filter(function(p) {
  return p.category === 'web';
});
console.log(webProjects.length);
console.log(webProjects.map(function(p) { return p.title; }));
filter keeps items matching the condition.
2
["A", "C"]
Question 5
Medium
What is the output?
const style = getComputedStyle(document.documentElement);
const accent = style.getPropertyValue('--accent');
console.log(typeof accent);
console.log(accent.trim());
CSS variable values are returned as strings, often with leading spaces.
string
#a855f7 (or whatever the current --accent value is)
Question 6
Medium
What is the output?
const words = ['hello', 'world'];
let i = 0;
i = (i + 1) % words.length;
console.log(i, words[i]);
i = (i + 1) % words.length;
console.log(i, words[i]);
i = (i + 1) % words.length;
console.log(i, words[i]);
The modulo operator wraps around to 0 after reaching the array length.
1 world
0 hello
1 world
Question 7
Hard
What is the output?
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
console.log(emailRegex.test('aarav@gmail.com'));
console.log(emailRegex.test('aarav@gmail'));
console.log(emailRegex.test('aarav gmail.com'));
console.log(emailRegex.test('@gmail.com'));
The regex requires: something@something.something with no spaces.
true
false
false
false
Question 8
Easy
Why do we use CSS custom properties (variables) for theming instead of changing individual styles in JavaScript?
Think about how many elements need to change when switching themes.
CSS variables let you define colors once and use them throughout the stylesheet. To switch themes, you only need to change the variable values (by toggling a CSS class like .light-mode), and every element using those variables updates automatically. Without variables, you would need JavaScript to find and update every single element's color individually.
Question 9
Medium
Why do we call observer.unobserve(entry.target) after the scroll animation plays?
What happens if we keep observing?
Without unobserve, the observer keeps watching the element. Every time it scrolls in and out of the viewport, the callback fires again. For animations that should only play once (like fade-in on first scroll), unobserve stops the observer from re-triggering. It also improves performance by reducing the number of elements being tracked.
Question 10
Hard
How does the typing effect use closures?
What variables does the tick function remember?
The tick function inside typeWriter forms a closure over the variables wordIndex, charIndex, isDeleting, element, words, and speed. These variables persist between setTimeout calls because the closure keeps them alive. Each time tick runs, it reads and modifies the state variables, then schedules itself again. Without closures, the state would be lost between setTimeout callbacks.
Question 11
Easy
What is the output?
const el = document.createElement('div');
el.style.opacity = '0';
console.log(el.style.opacity);
el.style.opacity = '1';
console.log(el.style.opacity);
style.opacity is set and read as a string.
0
1
Question 12
Medium
What is the output?
const links = document.querySelectorAll('a');
console.log(typeof links);
console.log(links instanceof NodeList);
console.log(Array.isArray(links));
querySelectorAll returns a NodeList, not an Array.
object
true
false
Question 13
Medium
What is the output?
const el = document.createElement('section');
el.id = 'about';
console.log(el.offsetTop);
The element is not in the DOM yet.
0
Question 14
Hard
What is the output?
const observer = new IntersectionObserver(function(entries) {
  entries.forEach(function(entry) {
    console.log(entry.isIntersecting);
  });
});
const el = document.createElement('div');
observer.observe(el);
What happens when you observe an element that is not in the DOM?
The callback fires immediately with false because the element is not in the viewport (it is not even in the DOM).
Question 15
Medium
What is the difference between opacity: 0 and display: none for hiding elements in scroll animations?
Think about whether the element takes up space.
opacity: 0 makes the element invisible but it still takes up space in the layout. display: none removes the element from the layout entirely, causing other elements to shift. For scroll animations, opacity: 0 is preferred because the element maintains its position and can smoothly transition to opacity: 1.
Question 16
Hard
How would you add keyboard accessibility to the hamburger menu?
Think about Enter key, Escape key, and focus management.
Add a keydown listener for Enter/Space to toggle the menu (matching button behavior). Add Escape key support to close the menu. When the menu opens, move focus to the first nav link. When it closes, return focus to the hamburger button. Add aria-expanded attribute to communicate the menu state to screen readers.

Mixed & Application Questions

Question 1
Easy
What is the output?
const el = document.createElement('div');
el.classList.add('animate-on-scroll');
console.log(el.classList.contains('visible'));
el.classList.add('visible');
console.log(el.classList.contains('visible'));
The element starts without the 'visible' class.
false
true
Question 2
Medium
What is the output?
localStorage.setItem('portfolioTheme', 'light');
const saved = localStorage.getItem('portfolioTheme');
if (saved === 'light') {
  console.log('Apply light mode');
} else {
  console.log('Apply dark mode');
}
localStorage stores and returns strings.
Apply light mode
Question 3
Medium
What is the output?
const word = 'JavaScript';
console.log(word.substring(0, 1));
console.log(word.substring(0, 4));
console.log(word.substring(0, word.length));
substring(start, end) extracts characters from start up to (but not including) end.
J
Java
JavaScript
Question 4
Hard
What is the output?
const sections = [
  { id: 'hero', top: 0, height: 800 },
  { id: 'about', top: 800, height: 400 },
  { id: 'projects', top: 1200, height: 600 }
];
const scrollY = 900;
sections.forEach(function(sec) {
  if (scrollY >= sec.top && scrollY < sec.top + sec.height) {
    console.log('Active: ' + sec.id);
  }
});
Find which section range contains scrollY = 900.
Active: about
Question 5
Hard
What is the output?
const bar = document.createElement('div');
bar.dataset.width = '85';
bar.style.width = '0%';

// Simulate Intersection Observer callback
bar.style.width = bar.dataset.width + '%';
console.log(bar.style.width);
dataset.width is a string. Concatenating with '%' creates the CSS value.
85%
Question 6
Easy
What is the output?
const el = document.createElement('div');
el.innerHTML = '

Quiz App

A quiz game

'; console.log(el.querySelector('h3').textContent); console.log(el.querySelector('p').textContent);
innerHTML creates child elements. querySelector finds them.
Quiz App
A quiz game
Question 7
Easy
What is the output?
const tech = ['HTML', 'CSS', 'JS'];
const tags = tech.map(function(t) {
  return '' + t + '';
}).join('');
console.log(tags);
map transforms each element, join combines them into a string.
<span>HTML</span><span>CSS</span><span>JS</span>
Question 8
Medium
What is the output?
localStorage.setItem('portfolioTheme', 'dark');
document.body.classList.remove('light-mode');
console.log(document.body.classList.contains('light-mode'));
console.log(localStorage.getItem('portfolioTheme'));
classList.remove removes the class. localStorage stores the string.
false
dark
Question 9
Medium
What is the output?
const name = '  Aarav  ';
const email = 'aarav@test.com';
const msg = 'Hi';

console.log(name.trim().length >= 2);
console.log(/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email));
console.log(msg.length >= 10);
Check each validation rule: name >= 2 chars after trim, valid email, message >= 10 chars.
true
true
false
Question 10
Hard
What is the output?
function typeStep(word, index) {
  return word.substring(0, index);
}

console.log(typeStep('Hello', 0));
console.log(typeStep('Hello', 3));
console.log(typeStep('Hello', 5));
substring(0, n) returns the first n characters.
(empty string)
Hel
Hello
Question 11
Hard
What is the output?
const root = document.documentElement;
root.style.setProperty('--accent', '#ff0000');
const computed = getComputedStyle(root).getPropertyValue('--accent');
console.log(computed.trim());
setProperty changes a CSS variable. getPropertyValue reads it.
#ff0000

Multiple Choice Questions

MCQ 1
What does scrollIntoView({ behavior: 'smooth' }) do?
  • A. Hides the element
  • B. Smoothly scrolls the page to make the element visible
  • C. Makes the element fade in
  • D. Removes the element from the page
Answer: B
B is correct. scrollIntoView scrolls the page so the element is visible in the viewport. The 'smooth' behavior creates a smooth animation instead of an instant jump.
MCQ 2
What is the purpose of CSS custom properties (--variable-name)?
  • A. To create JavaScript variables
  • B. To define reusable values that can be changed from one place
  • C. To add animations
  • D. To create media queries
Answer: B
B is correct. CSS custom properties let you define values once (:root) and use them throughout your CSS with var(). Changing the variable changes all uses automatically.
MCQ 3
Why do we call e.preventDefault() in the form submit handler?
  • A. To prevent the form from being styled
  • B. To prevent the page from refreshing when the form is submitted
  • C. To prevent JavaScript errors
  • D. To prevent the form from being visible
Answer: B
B is correct. By default, form submission refreshes the page. preventDefault() stops this so JavaScript can handle the form data without losing the page state.
MCQ 4
What does IntersectionObserver detect?
  • A. When a CSS animation ends
  • B. When an element enters or leaves the viewport
  • C. When the user clicks an element
  • D. When an API call finishes
Answer: B
B is correct. IntersectionObserver watches elements and fires a callback when they enter or leave the viewport (or any specified root element).
MCQ 5
How does the dark mode toggle work with localStorage?
  • A. localStorage changes the CSS automatically
  • B. Save the preference, then on page load check localStorage and apply the CSS class
  • C. localStorage sends the preference to the server
  • D. localStorage modifies the HTML file
Answer: B
B is correct. On toggle click, save the preference to localStorage. On page load, read from localStorage and add the appropriate CSS class. localStorage just stores the string; your JavaScript applies it.
MCQ 6
What CSS property is used to make elements initially hidden for scroll animations?
  • A. display: none
  • B. visibility: hidden
  • C. opacity: 0 combined with transform
  • D. position: absolute
Answer: C
C is correct. opacity: 0 with transform: translateY(30px) makes elements invisible and slightly below their final position. Adding the 'visible' class transitions them to opacity: 1 and translateY(0). display: none would remove them from layout.
MCQ 7
Why do we use the modulo operator (%) in the typing effect?
  • A. To calculate the typing speed
  • B. To cycle through the words array infinitely
  • C. To count the number of characters
  • D. To generate random words
Answer: B
B is correct. (wordIndex + 1) % words.length wraps the index back to 0 after reaching the end of the array, creating an infinite cycle through the words.
MCQ 8
What is the threshold option in IntersectionObserver?
  • A. The maximum number of elements to observe
  • B. The percentage of the element that must be visible to trigger the callback
  • C. The animation speed
  • D. The scroll position
Answer: B
B is correct. threshold: 0.1 means the callback fires when 10% of the element is visible. threshold: 1 would require the entire element to be visible. It can be a single number or an array of numbers.
MCQ 9
How does the active nav link highlighting determine which section is visible?
  • A. It uses IntersectionObserver for each section
  • B. It compares window.scrollY with each section's offsetTop and offsetHeight
  • C. It uses CSS :target pseudo-class
  • D. It checks which nav link was last clicked
Answer: B
B is correct. On each scroll event, the code checks if scrollY is between a section's top (offsetTop - navHeight) and bottom (top + offsetHeight). The nav link matching the visible section gets the active class.
MCQ 10
Why does the portfolio use data-width attributes on skill bars instead of hardcoded CSS widths?
  • A. To save bandwidth
  • B. So JavaScript can read the target width and animate from 0 to that value when the section is visible
  • C. Because CSS does not support percentage widths
  • D. For SEO purposes
Answer: B
B is correct. Skill bars start at width: 0. When the skills section scrolls into view, JavaScript reads data-width and sets the element's width to that percentage, creating a smooth animation via CSS transition.
MCQ 11
What is the hamburger menu pattern?
  • A. A menu shaped like a hamburger
  • B. Three horizontal lines that toggle the navigation menu on mobile devices
  • C. A dropdown menu for food ordering apps
  • D. A menu that slides from the bottom
Answer: B
B is correct. The hamburger menu is a common mobile UI pattern: three horizontal lines that, when tapped, reveal or hide the navigation links. It saves space on small screens.
MCQ 12
What technique does the typing effect use to create the animation loop?
  • A. setInterval with a fixed delay
  • B. requestAnimationFrame
  • C. setTimeout calling itself recursively (via closure)
  • D. CSS @keyframes animation
Answer: C
C is correct. The tick function uses setTimeout to call itself with a variable delay (slower for typing, faster for deleting, pause at end of word). This recursive approach via closure gives more control than setInterval.
MCQ 13
What does document.body.classList.toggle('light-mode') do?
  • A. Always adds the class
  • B. Always removes the class
  • C. Adds the class if absent, removes it if present
  • D. Toggles the body visibility
Answer: C
C is correct. classList.toggle adds the class if the element does not have it, or removes it if it does. This is perfect for dark/light mode switching.
MCQ 14
What is the purpose of the glassmorphism effect on project cards?
  • A. To improve page load speed
  • B. To create a modern, translucent card appearance with blur and transparency
  • C. To prevent click events
  • D. To make cards invisible
Answer: B
B is correct. Glassmorphism is a design trend that uses background blur, transparency, and subtle borders to create cards that look like frosted glass.
MCQ 15
Why does the portfolio use event.target.closest('.project-card') for click handling?
  • A. To find the nearest CSS class
  • B. To use event delegation -- find the ancestor card element when a child (like a tag or paragraph) is clicked
  • C. To measure the card's distance from the viewport
  • D. To close the card
Answer: B
B is correct. When a user clicks a tag or paragraph inside a card, event.target is the tag/paragraph, not the card. closest('.project-card') walks up the DOM to find the card ancestor.
MCQ 16
What does the scroll-to-top button do?
  • A. Scrolls to the bottom of the page
  • B. Refreshes the page
  • C. Smoothly scrolls to the top of the page
  • D. Opens a new tab
Answer: C
C is correct. The button calls window.scrollTo({ top: 0, behavior: 'smooth' }) to smoothly scroll back to the top.
MCQ 17
Why are CSS transitions used for the scroll animations instead of JavaScript animations?
  • A. CSS cannot do animations
  • B. CSS transitions are hardware-accelerated and more performant than JavaScript-driven animations
  • C. JavaScript animations do not work in browsers
  • D. CSS transitions only work on mobile
Answer: B
B is correct. CSS transitions for opacity and transform are hardware-accelerated by the browser's GPU, making them smoother and more performant than JavaScript-driven style changes.

Coding Challenges

Challenge 1: Add Skill Progress Bar Animation

Easy
Add a CSS transition to the skill bars so they animate from 0% to their target width when the skills section scrolls into view. Use Intersection Observer and data-width attributes.
Sample Input
User scrolls to the skills section
Sample Output
Skill bars smoothly expand from 0% to their target widths (90%, 85%, etc.)
Use CSS transition for the animation. Use IntersectionObserver to trigger it.
// CSS:
// .skill-fill { width: 0; transition: width 1s ease; }

const observer = new IntersectionObserver(function(entries) {
  entries.forEach(function(entry) {
    if (entry.isIntersecting) {
      entry.target.querySelectorAll('.skill-fill').forEach(function(bar) {
        bar.style.width = bar.dataset.width + '%';
      });
      observer.unobserve(entry.target);
    }
  });
}, { threshold: 0.2 });

observer.observe(document.querySelector('.skills-grid'));

Challenge 2: Add a Testimonials Carousel

Medium
Add a testimonials section with a carousel that automatically cycles through quotes. Show one testimonial at a time with a fade transition. Include left/right arrow buttons for manual navigation.
Sample Input
3 testimonials with name, quote, and role
Sample Output
Testimonials auto-rotate every 4 seconds. Arrows allow manual navigation.
Use setInterval for auto-rotation. Use classList for transitions.
const testimonials = [
  { name: 'Priya', role: 'Student', quote: 'Aarav built an amazing website for our school project!' },
  { name: 'Mr. Sharma', role: 'Teacher', quote: 'Impressive skills for a 16-year-old developer.' },
  { name: 'Rohan', role: 'Classmate', quote: 'He taught me JavaScript in just one week!' }
];
let current = 0;

function showTestimonial(index) {
  const el = document.getElementById('testimonialContent');
  el.style.opacity = 0;
  setTimeout(function() {
    el.innerHTML = '<p>"' + testimonials[index].quote + '"</p><strong>' + testimonials[index].name + '</strong><span> - ' + testimonials[index].role + '</span>';
    el.style.opacity = 1;
  }, 300);
}

setInterval(function() {
  current = (current + 1) % testimonials.length;
  showTestimonial(current);
}, 4000);

document.getElementById('prevBtn').addEventListener('click', function() {
  current = (current - 1 + testimonials.length) % testimonials.length;
  showTestimonial(current);
});

document.getElementById('nextBtn').addEventListener('click', function() {
  current = (current + 1) % testimonials.length;
  showTestimonial(current);
});

Challenge 3: Add a Blog Section

Medium
Add a blog section that displays blog post cards. Each card shows a title, date, excerpt, and 'Read More' link. Store blog data as an array of objects. Add a 'Load More' button that shows 3 posts at a time.
Sample Input
6 blog posts, initially showing 3
Sample Output
3 blog cards visible. Click 'Load More' to see 3 more. Button hides when all are shown.
Use array.slice() for pagination. Dynamically create card elements.
const posts = [
  { title: 'Getting Started with JS', date: '2026-04-01', excerpt: 'Learn the basics of JavaScript...' },
  { title: 'CSS Grid Layout', date: '2026-03-15', excerpt: 'Master CSS Grid for layouts...' },
  { title: 'DOM Manipulation', date: '2026-03-01', excerpt: 'How to change HTML with JS...' },
  { title: 'Async JavaScript', date: '2026-02-15', excerpt: 'Understanding promises...' },
  { title: 'Building APIs', date: '2026-02-01', excerpt: 'Create your own REST API...' },
  { title: 'React Basics', date: '2026-01-15', excerpt: 'Introduction to React...' }
];
let shown = 0;
const perPage = 3;

function loadMore() {
  const grid = document.getElementById('blogGrid');
  const batch = posts.slice(shown, shown + perPage);
  batch.forEach(function(post) {
    const card = document.createElement('div');
    card.classList.add('blog-card');
    card.innerHTML = '<h3>' + post.title + '</h3><time>' + post.date + '</time><p>' + post.excerpt + '</p><a href="#">Read More</a>';
    grid.appendChild(card);
  });
  shown += batch.length;
  if (shown >= posts.length) {
    document.getElementById('loadMoreBtn').style.display = 'none';
  }
}

document.getElementById('loadMoreBtn').addEventListener('click', loadMore);
loadMore();

Challenge 4: Add Project Search

Easy
Add a search input above the projects grid that filters projects in real-time as the user types. Search should match against the project title and description.
Sample Input
User types 'quiz' in the search box
Sample Output
Only the Quiz App project card is shown
Use the input event for real-time filtering. Convert to lowercase for case-insensitive search.
document.getElementById('projectSearch').addEventListener('input', function() {
  const query = this.value.toLowerCase().trim();
  const grid = document.getElementById('projectsGrid');
  grid.innerHTML = '';
  const matching = projects.filter(function(p) {
    return p.title.toLowerCase().includes(query) || p.desc.toLowerCase().includes(query);
  });
  matching.forEach(function(p) {
    const card = document.createElement('div');
    card.classList.add('project-card');
    card.innerHTML = '<h3>' + p.title + '</h3><p>' + p.desc + '</p>';
    grid.appendChild(card);
  });
});

Challenge 5: Add Animated Number Counters

Hard
Add a stats section with animated number counters (e.g., '5+ Projects', '1000+ Lines of Code', '3 Languages'). The numbers should count up from 0 to their target value when the section scrolls into view.
Sample Input
Section scrolls into view with targets: 5, 1000, 3
Sample Output
Numbers animate: 0->1->2->3->4->5, 0->100->200...->1000, 0->1->2->3
Use IntersectionObserver to trigger. Use setInterval or requestAnimationFrame for counting.
function animateCounter(element, target, duration) {
  let current = 0;
  const increment = target / (duration / 16);
  const timer = setInterval(function() {
    current += increment;
    if (current >= target) {
      current = target;
      clearInterval(timer);
    }
    element.textContent = Math.floor(current);
  }, 16);
}

const statsObserver = new IntersectionObserver(function(entries) {
  entries.forEach(function(entry) {
    if (entry.isIntersecting) {
      entry.target.querySelectorAll('.counter').forEach(function(el) {
        animateCounter(el, parseInt(el.dataset.target), 1500);
      });
      statsObserver.unobserve(entry.target);
    }
  });
}, { threshold: 0.3 });

statsObserver.observe(document.querySelector('.stats-section'));

Challenge 6: Add a Project Detail Modal

Hard
When a project card is clicked, show a modal overlay with full project details: title, description, technologies used, a screenshot placeholder, and links to live demo and source code. The modal should close when clicking the X button or the overlay background.
Sample Input
User clicks on the 'Quiz App' project card
Sample Output
Modal appears with Quiz App details, tech tags, and links. Clicking X or overlay closes it.
Create the modal dynamically. Use event delegation. Add a fade-in animation.
function showModal(project) {
  const overlay = document.createElement('div');
  overlay.classList.add('modal-overlay');
  overlay.innerHTML = '<div class="modal-content">' +
    '<button class="modal-close">X</button>' +
    '<h2>' + project.title + '</h2>' +
    '<p>' + project.desc + '</p>' +
    '<div class="tech-tags">' + project.tech.map(function(t) { return '<span class="tag">' + t + '</span>'; }).join('') + '</div>' +
    '<div class="modal-links">' +
    '<a href="#" class="btn btn-primary">Live Demo</a>' +
    '<a href="#" class="btn btn-outline">Source Code</a>' +
    '</div></div>';

  document.body.appendChild(overlay);
  requestAnimationFrame(function() { overlay.classList.add('visible'); });

  overlay.querySelector('.modal-close').addEventListener('click', function() {
    overlay.classList.remove('visible');
    setTimeout(function() { overlay.remove(); }, 300);
  });
  overlay.addEventListener('click', function(e) {
    if (e.target === overlay) {
      overlay.classList.remove('visible');
      setTimeout(function() { overlay.remove(); }, 300);
    }
  });
}

// Attach to project cards
document.getElementById('projectsGrid').addEventListener('click', function(e) {
  const card = e.target.closest('.project-card');
  if (card) {
    const title = card.querySelector('h3').textContent;
    const project = projects.find(function(p) { return p.title === title; });
    if (project) showModal(project);
  }
});

Need to Review the Concepts?

Go back to the detailed notes for this chapter.

Read Chapter Notes

Want to learn web development with a live mentor?

Explore our Frontend Masterclass