JavaScript Quiz From Basics to Advanced
True / False
True / False
JavaScript Pitfalls That Break “Correct-Looking” Code
Intermediate JavaScript errors often come from assumptions about scope, coercion, and async ordering. These mistakes show up as flaky UI behavior, missing data, or “works on my machine” bugs.
Scope, hoisting, and the temporal dead zone
- Accidental globals by assigning to an undeclared name. Fix by using "use strict" and always declaring with const or let.
- Assuming var is block-scoped.
varis function-scoped and hoisted, so loop callbacks can capture the same variable. Preferletin loops. - Reading let/const before declaration. That triggers a ReferenceError because of the temporal dead zone. Move reads below the declaration.
Equality, types, and “weird” values
- Using == and expecting intuitive coercion. Prefer
===, and explicitly convert withNumber(),String(), orBoolean(). - Forgetting that typeof null is "object". Use
value === nullfor null checks. - NaN comparisons.
NaN !== NaN, so check withNumber.isNaN(x).
Functions, this, and mutation
- Using arrow functions when you need dynamic this. Methods that rely on
thisusually needfunctionsyntax or explicit binding. - Shallow copying objects and arrays.
{...obj}and[...arr]do not clone nested structures. Clone deeply when required. - Unexpected mutation from
sort(),reverse(), or in-place updates. Copy before mutating.
Async ordering and error handling
- Not awaiting a Promise, which returns early and hides failures. Await or return the Promise from the function.
- Missing try/catch around await. Rejections become exceptions at the await site, so handle them where recovery makes sense.
JavaScript Basics-to-Advanced Quick Reference (Printable)
Use this as a quick recall sheet while reviewing answers. You can print this page or save it as a PDF from your browser print dialog.
Declarations and scope
- const: block-scoped, cannot reassign the binding (object contents can still mutate).
- let: block-scoped, can reassign.
- var: function-scoped, hoisted, avoid in new code.
Equality and type conversion
- Prefer === and !==.
- Truthiness:
false, 0, -0, 0n, "", null, undefined, NaNare falsy. Number.isNaN(x)checks NaN safely.typeof nullis"object", check null explicitly.
Functions and this
- Arrow functions capture lexical this and have no
arguments. - Regular functions have dynamic
thisbased on call-site. Usefn.call(obj, ...)orfn.bind(obj)when needed.
Objects, prototypes, and classes
- Property lookup follows the prototype chain: own props, then
Object.getPrototypeOf(obj), and so on. classis syntax over prototypes. Methods live onClassName.prototype.
Arrays and iteration
mapreturns a new array.forEachreturnsundefined.filterkeeps elements where the callback returns truthy.- Avoid
for...infor arrays. It iterates keys and inherited properties. Usefor...ofor array methods.
Promises and async/await
awaitpauses within anasyncfunction and unwraps the resolved value.- Use
Promise.allfor parallel work. One rejection rejects the whole result. - Error handling pattern:
async function load() {
try {
const res = await fetch("/api");
if (!res.ok) throw new Error("HTTP " + res.status);
return await res.json();
} catch (e) {
// recover or rethrow
throw e;
}
}
Modern operators
a?.boptional chaining avoids crashes on nullish receivers.a ?? busesbonly whenaisnullorundefined, not whenais0or"".
Worked Example: Fix a Buggy Async Search Handler (Scope, this, and Promises)
Scenario: a search box triggers API calls, but results arrive out of order and the UI sometimes shows stale data.
1) Start with the buggy code
class Search {
constructor(input, list) {
this.input = input;
this.list = list;
this.lastQuery = "";
input.addEventListener("input", this.onInput);
}
async onInput(e) {
this.lastQuery = e.target.value;
const res = await fetch("/api?q=" + this.lastQuery);
const items = await res.json();
this.render(items);
}
render(items) {
this.list.textContent = items.join(", ");
}
}
2) Identify the first failure: this binding
addEventListener calls the handler with this set to the input element (or undefined in strict mode), not the class instance. So this.render can be missing or wrong.
Fix by binding once in the constructor or by making the handler an arrow property.
3) Identify the second failure: out-of-order responses
If the user types fast, an earlier request can resolve after a later request. The late arrival overwrites the latest results. Track a request token and ignore stale responses.
4) Correct implementation
class Search {
constructor(input, list) {
this.input = input;
this.list = list;
this.reqId = 0;
this.onInput = this.onInput.bind(this);
input.addEventListener("input", this.onInput);
}
async onInput(e) {
const q = e.target.value;
const id = ++this.reqId;
const res = await fetch("/api?q=" + encodeURIComponent(q));
if (!res.ok) throw new Error("HTTP " + res.status);
const items = await res.json();
if (id !== this.reqId) return; // stale
this.render(items);
}
render(items) {
this.list.textContent = items.join(", ");
}
}
This example checks three quiz themes: call-site this, async/await error paths, and race conditions between Promises.
JavaScript Quiz FAQ: Scope, Async Semantics, and Modern Syntax
What topics typically separate “basics” from “advanced” JavaScript questions?
Basics focus on syntax and everyday APIs like arrays, objects, and functions. Advanced questions usually target JavaScript’s execution model and edge cases: scope rules (including the temporal dead zone), prototype chain lookup, this binding, coercion rules behind ==, and the event loop behavior that affects Promises, async/await, and timers.
Why do arrow functions cause bugs with this in event handlers and class methods?
Arrow functions capture this from the surrounding scope. That is great for callbacks where you want the outer this, but it is wrong when you need a dynamic receiver. A DOM event listener that passes a regular function will set this to the element in many environments, so mixing handler styles without intent can break property access and method calls.
How should I reason about Promise ordering versus setTimeout ordering?
Promise reactions (then/catch/finally) are scheduled as microtasks. Timers like setTimeout schedule macrotasks. After the current call stack completes, the runtime drains microtasks before running the next macrotask. If your answer depends on print order, first list synchronous logs, then microtasks, then timers.
What is the safest way to avoid accidental mutation in quiz-style code snippets?
Assume many array and object operations share references. Prefer non-mutating patterns: use spread to copy arrays and objects before changing them, and use map, filter, and reduce to produce new arrays. Watch for mutators like sort, reverse, push, and direct property assignment on shared objects.
Should I use async/await everywhere instead of chaining then()?
Async/await improves readability for sequential steps and try/catch error handling. Promise chaining is still useful for small transformations, for composing reusable helpers, and for concurrency patterns. In either style, make sure you return Promises from functions that callers need to await, and always decide where errors are handled versus rethrown.
Any good cross-training if I struggle with control flow or data transformations?
If control flow and scoping are the issue, practicing in another language can help you see what is JavaScript-specific. Use Check Your Python Programming Skills to compare function scope, closures, and error handling patterns. If data shaping is the issue, Practice Writing SQL Queries Correctly for filtering and grouping, then map those concepts back to JavaScript arrays.
Looking for more? Browse Technology & IT quizzes on QuizWiz or explore the full professional training quizzes on QuizWiz.