JavaScript MCQs multiple-choice questions with answers & explanations
All 42 JavaScript quiz questions on one page. Pick an answer in your head, then open Show answer to check it and read why. Want a score and a timer? Take them as a quiz instead.
- 1.easy
What does
typeof nullreturn?- A
'null' - B
'undefined' - C
'object' - D
'NaN'
Show answer
Answer: C (
'object')typeof nullis'object', a bug from the first JavaScript engine that was kept for backward compatibility. To test for null, compare directly withvalue === null. - A
- 2.easy
What does this log?
console.log(1 + '2' - 1);- A
11 - B
2 - C
'111' - D
NaN
Show answer
Answer: A (
11)Evaluated left to right:
1 + '2'concatenates to'12'because one operand is a string.-has no string meaning, so'12' - 1converts to numbers and gives11. - A
- 3.easy
What does this log?
const count = 0; console.log(count || 10, count ?? 10);- A
0 0 - B
10 10 - C
10 0 - D
0 10
Show answer
Answer: C (
10 0)||falls back on any falsy value, and0is falsy, so it gives10.??only falls back onnullorundefined, so it keeps0. Use??for defaults when0or an empty string are valid values. - A
- 4.mid
Which of these expressions evaluates to
false?- A
null == undefined - B
'' == 0 - C
'0' == false - D
null == 0 - E
[] == false
Show answer
Answer: D (
null == 0)With
==,nullis only loosely equal toundefined(and itself). It is never converted to a number, sonull == 0isfalse. The others coerce:'' == 0compares0 == 0,'0' == falsebecomes0 == 0, and[] == falsebecomes'' == 0. - A
- 5.mid
What does this log?
const values = [NaN]; console.log(values.indexOf(NaN), values.includes(NaN));- A
0 true - B
-1 false - C
-1 true - D
0 false
Show answer
Answer: C (
-1 true)indexOfuses strict equality, andNaN === NaNisfalse, so it cannot findNaNand returns-1.includesuses the SameValueZero algorithm, which treatsNaNas equal to itself, so it returnstrue. - A
- 6.hard
What does
[] == ![]evaluate to?- A
true - B
false - CIt throws a
TypeError
Show answer
Answer: A (
true)![]isfalse, because every object is truthy. Then[] == false: the boolean becomes0, the array goes through ToPrimitive to'', and''becomes0. So it is0 == 0, which istrue. - A
- 7.easy
What does this log?
function test() { if (true) { var x = 1; let y = 2; } console.log(typeof x, typeof y); } test();- A
number number - B
number undefined - C
undefined undefined - DIt throws a
ReferenceError
Show answer
Answer: B (
number undefined)varis function-scoped, soxis visible after theifblock.letis block-scoped, so noyexists at theconsole.log.typeofon an undeclared name returns'undefined'instead of throwing. - A
- 8.easy
What does this log?
console.log(typeof declared, typeof expressed); function declared() {} var expressed = function () {};- A
function function - B
undefined undefined - CIt throws a
ReferenceError - D
function undefined
Show answer
Answer: D (
function undefined)Function declarations are hoisted along with their body, so
declaredis already a function. Forvar expressed = function () {}, only thevardeclaration is hoisted and initialised toundefined; the function is assigned when that line runs. - A
- 9.mid
What happens when this runs?
let x = 'outer'; { console.log(x); let x = 'inner'; }- AIt logs
'outer' - BIt logs
undefined - CIt throws a
ReferenceError - DIt logs
'inner'
Show answer
Answer: C (It throws a
ReferenceError)The inner
let xis hoisted to the top of the block, so it shadows the outerxfor the whole block. Before its declaration line runs, it is in the temporal dead zone, and reading it throwsReferenceError: Cannot access 'x' before initialization. - AIt logs
- 10.hard
What happens when this runs?
console.log(typeof notDeclared); console.log(typeof later); let later = 1;- A
undefined, thenundefined - B
undefined, thennumber - C
undefined, then aReferenceError - DA
ReferenceErroron the first line
Show answer
Answer: C (
undefined, then aReferenceError)typeofis safe on names that are not declared anywhere, so the first line logs'undefined'.lateris declared withletin this scope, so it exists but is in the temporal dead zone, and eventypeofthrows aReferenceErrorthere. - A
- 11.mid
What does this code log?
for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 0); }- A
0 1 2 - B
3 3 3 - C
undefinedthree times - D
0 0 0
Show answer
Answer: B (
3 3 3)varis function-scoped, so all three callbacks close over the samei, which is3by the time they run. Useletto get a fresh binding per iteration. - A
- 12.easy
What does this log?
function makeCounter() { let count = 0; return () => ++count; } const a = makeCounter(); const b = makeCounter(); a(); a(); console.log(a(), b());- A
3 1 - B
3 4 - C
1 1 - D
2 1
Show answer
Answer: A (
3 1)Each call to
makeCountercreates a newcountvariable, and the returned function closes over its own copy.ahas been called twice already, so the third call returns3, whilebstarts fresh and returns1. - A
- 13.mid
What does this log?
const obj = { value: 42, getArrow() { return () => this.value; }, }; const fn = obj.getArrow(); const other = { value: 7, fn }; console.log(fn(), other.fn());- A
42 7 - B
undefined 7 - CIt throws a
TypeError - D
42 42
Show answer
Answer: D (
42 42)An arrow function has no
thisof its own. It capturesthisfrom where it was created, here thegetArrowcall wherethiswasobj. Calling it later asother.fn()cannot rebind it, so both calls return42. - A
- 14.mid
What does this log?
function show() { return this.x; } const a = { x: 1 }; const b = { x: 2 }; const bound = show.bind(a); console.log(bound.call(b), bound.bind(b)());- A
2 2 - B
1 2 - C
1 1 - D
2 1
Show answer
Answer: C (
1 1)bindreturns a function whosethisis permanently fixed. Latercall,applyor anotherbindcannot change it, so both calls returna.x. The only thing that overrides a boundthisis calling the bound function withnew. - A
- 15.mid
In strict mode (for example inside an ES module), what happens when this runs?
const user = { name: 'Ada', greet() { return 'Hi ' + this.name; }, }; const greet = user.greet; console.log(greet());- AIt logs
'Hi Ada' - BIt logs
'Hi undefined' - CIt throws a
TypeError - DIt logs
'Hi '
Show answer
Answer: C (It throws a
TypeError)Assigning
user.greetto a variable drops the receiver, sogreet()is a plain call. In strict mode a plain call getsthis === undefined, and readingundefined.namethrows. Sloppy scripts would use the global object instead and log'Hi undefined'in Node. Fix it withuser.greet.bind(user)or an arrow wrapper. - AIt logs
- 16.mid
What does this log?
const parent = { greeting: 'hi' }; const child = Object.create(parent); child.greeting = 'hey'; delete child.greeting; console.log(child.greeting, Object.keys(child).length);- A
undefined 0 - B
hey 1 - C
hi 1 - D
hi 0
Show answer
Answer: D (
hi 0)Assigning
child.greetingcreates an own property that shadows the inherited one; it does not changeparent.deleteremoves only that own property, so the lookup falls through to the prototype again and finds'hi'.Object.keyslists own enumerable keys only, so it is empty. - A
- 17.hard
What does this log?
function Animal() {} Animal.prototype.speak = () => 'generic'; const a = new Animal(); Animal.prototype = { speak: () => 'woof' }; const b = new Animal(); console.log(a.speak(), b.speak(), a instanceof Animal);- A
woof woof true - B
generic woof true - C
generic woof false - D
woof woof false
Show answer
Answer: C (
generic woof false)newlinks each instance to whatever objectAnimal.prototypeis at that moment.akeeps its link to the old object, so it still says'generic'.instanceofchecks whether the currentAnimal.prototypeis ina's chain, and it is not, so it returnsfalse. Mutating the prototype would affect both; replacing it does not. - A
- 18.hard
What does this log?
class Base { constructor() { this.init(); } init() {} } class Child extends Base { label = 'child'; init() { console.log(this.label); } } new Child();- A
'child' - B
undefined - CIt throws a
TypeError - DNothing:
Base's emptyinitruns
Show answer
Answer: B (
undefined)The overridden
initdoes run, becausethisis already aChildduring the base constructor. But a derived class initialises its fields only aftersuper()returns, solabelhas not been assigned yet and the log showsundefined. Avoid calling overridable methods from constructors. - A
- 19.mid
In what order are the numbers logged?
console.log('1'); setTimeout(() => console.log('2'), 0); Promise.resolve().then(() => console.log('3')); queueMicrotask(() => console.log('4')); console.log('5');- A
1 2 3 4 5 - B
1 5 2 3 4 - C
1 5 4 3 2 - D
1 5 3 4 2
Show answer
Answer: D (
1 5 3 4 2)Synchronous code runs first (
1,5). Then the microtask queue is drained in the order tasks were queued: the promise reaction3, then thequeueMicrotaskcallback4. ThesetTimeoutcallback is a macrotask, so2runs only after all microtasks. - A
- 20.mid
What order are the letters logged in?
async function run() { console.log('a'); await null; console.log('b'); } console.log('c'); run(); console.log('d');- A
c a b d - B
c a d b - C
c d a b - D
a b c d
Show answer
Answer: B (
c a d b)An
asyncfunction runs synchronously until its firstawait, soalogs immediately afterc.awaitsuspendsrunand schedules the rest as a microtask, even for a non-promise likenull. The caller continues withd, andbruns once the call stack is empty. - A
- 21.mid
What order are the letters logged in?
const p = new Promise((resolve) => { console.log('A'); resolve('B'); console.log('C'); }); p.then((v) => console.log(v)); console.log('D');- A
A B C D - B
D A C B - C
A C D B - D
A C B D
Show answer
Answer: C (
A C D B)The executor function runs synchronously inside
new Promise, soAandClog immediately; callingresolvedoes not stop the executor..thencallbacks always run asynchronously as microtasks, even on an already-resolved promise, soDlogs beforeB. - A
- 22.hard
What order are the numbers logged in?
Promise.resolve() .then(() => console.log(1)) .then(() => console.log(2)); Promise.resolve() .then(() => console.log(3)) .then(() => console.log(4));- A
1 3 2 4 - B
1 2 3 4 - C
3 4 1 2 - D
1 3 4 2
Show answer
Answer: A (
1 3 2 4)Both first-level callbacks are queued as microtasks right away, so
1and3run first. Eachthenreturns a new promise, and a second-level callback is queued only when that promise resolves, which happens after1or3has run. So the chains interleave:1 3 2 4. - A
- 23.hard
What order are the labels logged in?
setTimeout(() => { console.log('t1'); Promise.resolve().then(() => console.log('p1')); }, 0); setTimeout(() => console.log('t2'), 0); Promise.resolve().then(() => console.log('p0'));- A
t1 t2 p0 p1 - B
p0 t1 t2 p1 - C
t1 p1 t2 p0 - D
p0 t1 p1 t2
Show answer
Answer: D (
p0 t1 p1 t2)After the script finishes, the pending microtask
p0runs first. Then the first timer runs and queuesp1. The microtask queue is drained after every macrotask, sop1runs before the second timert2. Browsers and Node 11+ agree on this order. - A
- 24.mid
What happens when this runs?
async function load() { throw new Error('boom'); } try { load(); console.log('after'); } catch (e) { console.log('caught'); }- AIt logs
caught - BIt logs
after, then the rejection is reported as unhandled - CIt logs
after, thencaught - DNothing is logged, because
load()throws synchronously
Show answer
Answer: B (It logs
after, then the rejection is reported as unhandled)Calling an
asyncfunction never throws synchronously: thethrowturns into a rejected promise that the call returns. Nothing awaits it, so thetryblock finishes normally and the rejection goes unhandled (in Node 15+ that crashes the process). Useawait load()inside an async function, orload().catch(...). - AIt logs
- 25.mid
You request the same file from three mirrors and want the first successful response, ignoring failures unless every mirror fails. Which combinator fits?
- A
Promise.any - B
Promise.race - C
Promise.all - D
Promise.allSettled
Show answer
Answer: A (
Promise.any)Promise.anyfulfils with the first promise to fulfil and rejects with anAggregateErroronly if all of them reject.Promise.racesettles with the first promise to settle, so a fast failure would win.Promise.allrejects on the first failure, andPromise.allSettledwaits for every mirror. - A
- 26.mid
What does this log?
console.log(['1', '2', '3'].map(parseInt));- A
[1, 2, 3] - B
[1, NaN, NaN] - C
[1, NaN, 3] - D
[NaN, NaN, NaN]
Show answer
Answer: B (
[1, NaN, NaN])mapcalls its callback with(value, index, array), andparseInttakes(string, radix). So the calls areparseInt('1', 0)(radix 0 means the default, giving1),parseInt('2', 1)(radix 1 is invalid, soNaN) andparseInt('3', 2)(3 is not a binary digit, soNaN). Use.map(Number)or an arrow function. - A
- 27.easy
What does this log?
console.log([10, 1, 5, 100].sort());- A
[1, 5, 10, 100] - B
[100, 10, 5, 1] - C
[10, 1, 5, 100] - D
[1, 10, 100, 5]
Show answer
Answer: D (
[1, 10, 100, 5])Without a comparator,
sortconverts elements to strings and compares them by UTF-16 code units, so'100'comes before'5'. Usearr.sort((a, b) => a - b)for numbers.sortalso mutates the array;toSortedreturns a sorted copy. - A
- 28.mid
What does this log?
const cache = {}; const a = { id: 'a' }; const b = { id: 'b' }; cache[a] = 1; cache[b] = 2; console.log(cache[a]);- A
2 - B
1 - C
undefined - DIt throws a
TypeError
Show answer
Answer: A (
2)Plain object keys are strings or symbols. Both objects are converted with
String()and become'[object Object]', so the second assignment overwrites the first andcache[a]reads2. Use aMapwhen you need objects as keys. - A
- 29.hard
What does this log?
const obj = { b: 1, 2: 'two', a: 2, 1: 'one' }; console.log(Object.keys(obj));- A
['b', '2', 'a', '1'] - B
['1', '2', 'a', 'b'] - C
['1', '2', 'b', 'a'] - DThe order is not guaranteed
Show answer
Answer: C (
['1', '2', 'b', 'a'])Own property order is defined: integer-like keys first in ascending numeric order, then other string keys in insertion order, then symbols (which
Object.keysskips). So1and2jump ahead, whilebstays beforea. - A
- 30.easy
What does this log?
const original = { name: 'Ada', tags: ['math'] }; const copy = { ...original }; copy.name = 'Grace'; copy.tags.push('code'); console.log(original.name, original.tags.length);- A
Ada 2 - B
Ada 1 - C
Grace 2 - D
Grace 1
Show answer
Answer: A (
Ada 2)Object spread makes a shallow copy.
nameholds a primitive, so changingcopy.namedoes not affect the original.tagsis the same array in both objects, so thepushshows up inoriginal.tagstoo. UsestructuredClonefor a deep copy. - A
- 31.easy
What does this log?
const config = Object.freeze({ theme: { dark: false } }); config.theme.dark = true; console.log(config.theme.dark);- A
true - B
false - CIt throws a
TypeError - D
undefined
Show answer
Answer: A (
true)Object.freezeis shallow. It makesconfig's own properties read-only, butconfig.themestill points to an ordinary, unfrozen object, so itsdarkproperty can change, even in strict mode. Deep freezing needs a recursive helper. - A
- 32.mid
What does this log?
const data = { a: undefined, b: () => 1, c: NaN, d: null }; console.log(JSON.stringify(data));- A
{"a":null,"b":null,"c":null,"d":null} - B
{"c":null,"d":null} - C
{"c":NaN,"d":null} - D
{"a":undefined,"c":NaN,"d":null}
Show answer
Answer: B (
{"c":null,"d":null})Object properties whose value is
undefined, a function or a symbol are left out.NaNandInfinityare not valid JSON numbers, so they becomenull, andnullstaysnull. Inside arrays,undefinedand functions becomenullinstead of being dropped. - A
- 33.hard
Which value makes
structuredClone(value)throw?- AAn object with a circular reference
- BAn object with a method
- CA
Dateinstance - DAn object containing a
Mapand aSet
Show answer
Answer: B (An object with a method)
The structured clone algorithm handles
Map,Set,Date,RegExp, typed arrays and circular references, but functions cannot be cloned, so an object with a method throws aDataCloneError. It also drops prototypes, so class instances come back as plain objects. - 34.hard
What does this log?
function* gen() { const x = yield 1; console.log('got', x); yield x * 2; } const it = gen(); console.log(it.next(5).value); console.log(it.next(10).value);- A
1,got 5,10 - B
5,got 10,20 - C
1,got undefined,NaN - D
1,got 10,20
Show answer
Answer: D (
1,got 10,20)The first
next()runs the generator up to the firstyieldand returns1; its argument5is ignored because noyieldis waiting to receive it.next(10)resumes the generator, and10becomes the value of the pausedyield 1expression, soxis10and the nextyieldproduces20. - A
- 35.hard
Both files are ES modules. What does
main.jslog?// counter.js export let count = 0; export function increment() { count++; } // main.js import { count, increment } from './counter.js'; increment(); console.log(count);- A
1 - B
0 - CA
TypeError: assignment to a constant - D
undefined
Show answer
Answer: A (
1)ES module imports are live, read-only bindings to the exporting module's variable, not copies, so
main.jssees the updated1. Only the exporting module can reassign it;count = 5insidemain.jswould throw aTypeError. With CommonJS, destructuring the result ofrequire()copies the value, which would stay0. - A
- 36.mid
What does this log?
function check() { try { return 'try'; } finally { return 'finally'; } } console.log(check());- A
'try' - BA
SyntaxError - C
'try', then'finally' - D
'finally'
Show answer
Answer: D (
'finally')A
finallyblock always runs, even afterreturn. If it executes its ownreturn, that completion replaces the pending one, so the function returns'finally'. A thrown error would be silently swallowed the same way, which is why linters flagreturninsidefinally. - A
- 37.mid
In a browser, the user clicks the
span. What does the listener log?// <ul id="list"><li><button>Save <span>icon</span></button></li></ul> const list = document.getElementById('list'); list.addEventListener('click', (event) => { console.log(event.target.tagName, event.currentTarget.tagName); });- A
UL UL - B
BUTTON UL - C
SPAN UL - D
SPAN SPAN
Show answer
Answer: C (
SPAN UL)event.targetis the element where the event started, the innermost element clicked, here theSPAN.event.currentTargetis the element whose listener is running, theUL. That is why delegation code usually usesevent.target.closest('button')to find the element it cares about. - A
- 38.mid
In a modern browser, the user clicks
#inner. What order are the messages logged in?// <div id="outer"><div id="inner">Click me</div></div> const outer = document.getElementById('outer'); const inner = document.getElementById('inner'); outer.addEventListener('click', () => console.log('outer bubble')); outer.addEventListener('click', () => console.log('outer capture'), true); inner.addEventListener('click', () => console.log('inner bubble')); inner.addEventListener('click', () => console.log('inner capture'), true);- Ainner capture, inner bubble, outer capture, outer bubble
- Bouter capture, inner capture, inner bubble, outer bubble
- Couter bubble, outer capture, inner bubble, inner capture
- Douter capture, inner bubble, inner capture, outer bubble
Show answer
Answer: B (outer capture, inner capture, inner bubble, outer bubble)
An event travels down from the window in the capture phase, reaches the target, then bubbles back up. Capture listeners on ancestors fire first, then the listeners on the target, then bubble listeners on ancestors. On the target itself, current browsers also run capture listeners before bubble ones (older browsers used registration order).
- 39.easy
A listener added with
addEventListeneron an<a href>link must stop the browser from following the link. What does that?- A
event.stopPropagation() - B
event.stopImmediatePropagation() - CReturning
falsefrom the listener - D
event.preventDefault()
Show answer
Answer: D (
event.preventDefault())preventDefault()cancels the browser's default action, such as navigation, form submission or toggling a checkbox.stopPropagation()only stops the event from reaching other elements; the link still navigates. Returningfalsecancels the default only inonclick-style handler properties and inline attributes, not inaddEventListenercallbacks. - A
- 40.easy
In a browser, which storage is scoped to a single tab and cleared when that tab is closed?
- A
localStorage - B
sessionStorage - CA cookie without
ExpiresorMax-Age - DIndexedDB
Show answer
Answer: B (
sessionStorage)sessionStorageis per origin and per tab: another tab on the same site gets its own copy, and the data survives reloads but not closing the tab.localStorageand IndexedDB persist and are shared across tabs. A session cookie lives until the browser session ends and is shared by every tab. - A
- 41.easy
In a browser, what does this log?
localStorage.setItem('user', { name: 'Ada' }); console.log(localStorage.getItem('user'));- A
{ name: 'Ada' } - BThe string
[object Object] - C
null - DIt throws a
TypeError
Show answer
Answer: B (The string
[object Object])Web Storage only stores strings, and
setItemconverts its value withString(), so the object is saved as'[object Object]'. Store objects withJSON.stringifyand read them back withJSON.parse. - A
- 42.mid
Why is a
WeakMapa good fit for storing metadata about DOM nodes?- AIt can be iterated to list every node that has metadata
- BIts lookups are much faster than those of a
Map - CIts keys are held weakly, so an entry can be garbage-collected once its node is otherwise unreachable
- DIt accepts strings, so you can key it by element id
Show answer
Answer: C (Its keys are held weakly, so an entry can be garbage-collected once its node is otherwise unreachable)
A
Mapholds strong references to its keys, so DOM nodes used as keys can never be collected after removal: a leak. AWeakMapdoes not keep its keys alive, and when a key is collected its value goes with it. The price is that keys must be objects (or non-registered symbols), and there is no iteration orsize.