JavaScript Interview Questions: Core Concepts & Practice Quiz
Reviewed by Mark Dickie · Last updated
JavaScript is a single-threaded, interpreted scripting language that runs in the browser and on the server via Node.js, built around an event-driven, non-blocking I/O model. For interviews at any level, you should be confident on the core type system and coercion rules, how closures and scope chains work, the event loop and the call stack, and the async primitives — callbacks, Promises, and async/await. Prototype-based inheritance trips up a lot of candidates too, so if you can explain [[Prototype]] without reaching for a metaphor, you are already ahead of most people in the room.
What interviewers actually test
The questions tend to cluster around a handful of topics regardless of the company. Here is a map of those areas and the underlying concept each one is really probing:
| Topic area | Core concept being probed |
|---|---|
| var / let / const | Hoisting, temporal dead zone, block vs. function scope |
| Closures | Lexical environment, memory, factory functions |
| this keyword | Binding rules: default, implicit, explicit (call/apply/bind), new |
| Prototypes & classes | [[Prototype]] chain, Object.create, ES2015 class as syntax sugar |
| Event loop | Call stack, task queue, microtask queue, Promise resolution order |
| Async patterns | Callbacks → Promises → async/await, error handling with try/catch |
| Type coercion | Loose equality (==), typeof, Number() vs + vs parseInt |
| Array/object methods | map, reduce, filter, flat, Object.keys, spread vs. rest |
How to pace your preparation
The difficulty range here runs from beginner syntax recall up to problems that require you to reason about engine internals. A good order of study:
- Types and coercion first. Coercion catches people off guard more than any other topic. Nail
==vs===, falsy values, andtypeof nullbefore anything else. - Scope and closures. Read the spec definition of a lexical environment, then write three closure-based examples from scratch — a counter, a memoizer, and a partial application function.
thisbinding. Work through each of the four binding rules in order: default, implicit, explicit,new. Arrow functions get a separate rule: they inheritthisfrom their enclosing lexical scope.- The event loop. Draw the call stack and both queues on paper. Then predict the console output of a short snippet mixing
setTimeout(fn, 0), a resolved Promise, and a synchronousconsole.log. Check your answer before running it. - Prototype chain and
class. Write an inheritance example with plainObject.create, then rewrite it withclass/extends. Confirming they produce the same prototype chain is the whole point.
ES2023 (the current major release as of this writing) added Array.prototype.toSorted, toReversed, toSpliced, and with — non-mutating counterparts to the old mutating methods. Those are fresh enough that an interviewer asking about immutable array operations might expect you to know them.
At a glance
| Questions | 15 |
|---|---|
| Difficulty | 2–5 of 5 |
| Formats | Multiple choice, Multiple answer, True / false, Code output, Find the bug, Short answer, Flashcard |
What you'll review
- primitive types
- equality operators
- type coercion
- array methods
- var let const
- nan handling
- promise ordering
- higher order functions
- closures
- this rules
- call apply bind
- hoisting
- tdz
- new operator
- optional chaining
Practice questions
JavaScript/types-coercion/primitive-types
What does typeof null evaluate to?
Options
- "object"
- "null"
- "undefined"
- "number"
Show answer
It evaluates to the string object. This is a long-standing bug from the very first JavaScript implementation that has been kept for backward compatibility, so null reports as type object despite being a primitive. To reliably test for null, compare directly with value === null.
typeof null returns "object" — a long-standing bug from the first JS implementation that is kept for backward compatibility. Use value === null to test for null.
JavaScript/types-coercion/equality-operators
Which of these comparisons evaluates to false?
Options
- 0 == '0'
- 0 == ''
- '' == '0'
- 0 == false
Show answer
'' == '0' is the one that is false. When both operands are strings, loose equality does no coercion — it just compares the two strings, and an empty string differs from '0'. The other comparisons each coerce their operands to the number 0, which compares equal.
== between two strings does no coercion: '' and '0' are simply different strings, so it is false. The other three coerce their operands to the number 0, which compares equal.
JavaScript/types-coercion/type-coercion
Which of these values are falsy in JavaScript?
Options
- 0
- '0'
- []
- NaN
Show answer
The falsy values here are 0 and NaN. JavaScript's complete falsy set is false, 0, -0, 0n, the empty string, null, undefined, and NaN. The string '0' is a non-empty string and an empty array [] is an object, so both of those are truthy.
The falsy values are false, 0, -0, 0n, '', null, undefined, and NaN. The string '0' and an empty array [] are both objects/non-empty strings and are truthy.
JavaScript/arrays/array-methods
Which array methods mutate the array they are called on?
Options
- map
- splice
- sort
- filter
Show answer
splice and sort are the mutating methods — they change the array in place. map and filter are non-mutating: each returns a brand-new array and leaves the original untouched. This distinction matters when you rely on the source array staying intact after the call.
splice and sort mutate the array in place. map and filter are non-mutating — they return a new array and leave the original untouched.
JavaScript/scope-closures/var-let-const
Declaring an object with const makes the object immutable.
Show answer
False. const only prevents reassigning the binding itself — the object it points to can still have its properties added, changed, or deleted. If you need the contents to be immutable, use Object.freeze for a shallow freeze of the object's own properties.
const only prevents reassigning the binding. The object it points to can still have its properties changed. Use Object.freeze for shallow immutability.
JavaScript/types-coercion/nan-handling
NaN === NaN evaluates to false.
Show answer
True. NaN is the only JavaScript value that is not equal to itself, so NaN === NaN is false. This is why you cannot test for it with x === NaN; use Number.isNaN(x) instead, which correctly reports whether a value is the special Not-a-Number value.
NaN is the only JavaScript value that is not equal to itself. Use Number.isNaN(x) (not x === NaN) to test for it.
JavaScript/event-loop/promise-ordering
In what order are the four values logged?
console.log('a');
setTimeout(() => console.log('b'), 0);
Promise.resolve().then(() => console.log('c'));
console.log('d');Show answer
a
d
c
b
Synchronous code runs first (a, d). The microtask queue (the resolved Promise's .then) drains before the next macrotask, so c logs before the setTimeout callback b.
JavaScript/functions/higher-order-functions
doubled logs [undefined, undefined, undefined]. What is wrong?
const nums = [1, 2, 3];
const doubled = nums.map(n => { n * 2 });
console.log(doubled);Options
- The arrow uses a block body
{ ... }with noreturn, so every element isundefined mapmutatesnumsinstead of returning a new arraymapcannot be called on an array literalconsole.logneedsJSON.stringifyto print an array
Show answer
The arrow uses a block body { ... } with no return, so every element is undefined
A block-bodied arrow n => { n * 2 } has a statement body and no return, so it returns undefined for each element. Use the concise body n => n * 2 (or add return n * 2).
JavaScript/scope-closures/closures
What is a closure, and give one practical use for it.
Show answer
A closure is a function bundled together with references to its surrounding lexical scope, so it can keep accessing those variables even after the outer function has returned. A common use is data privacy — e.g. a counter factory that keeps count private and exposes only an increment function.
Closures capture variables by reference from the scope in which a function was defined. They power module patterns, data privacy, partial application, and stable callbacks.
JavaScript/this-binding/this-rules
In strict mode, what is this inside a regular function called as a standalone function (e.g. fn())?
Show answer
undefined. In strict mode this is not coerced to the global object, so a plain function call leaves it undefined.
Outside strict mode the same call would set this to the global object (window/globalThis). Arrow functions ignore call-site this entirely and use the enclosing scope's.
JavaScript/this-binding/call-apply-bind
Name the three function methods that explicitly set this, and how they differ.
Show answer
call(thisArg, ...args) and apply(thisArg, argsArray) invoke immediately (args spread vs. array); bind(thisArg, ...args) returns a new function with this permanently fixed.
call and apply differ only in how arguments are passed. bind does not invoke — it produces a bound function you call later.
JavaScript/scope-closures/hoisting
Given console.log(typeof a, typeof b); var a = 1; function b() {} at the top level, what is logged?
Options
undefined functionfunction functionundefined undefined- A
ReferenceErroris thrown
Show answer
It logs undefined function. Hoisting raises declarations to the top of the scope, but a function declaration is hoisted together with its body, so b is already callable. A var is hoisted too, yet only initialized to undefined until its assignment runs — so typeof a reports undefined.
Hoisting raises declarations to the top of the scope. A function declaration is hoisted with its body, so b is already a function. A var is hoisted but initialized to undefined until its assignment runs, so typeof a is "undefined".
JavaScript/scope-closures/tdz
What happens when this runs? { console.log(x); let x = 5; }
Options
- It throws a
ReferenceErrorbecausexis in the temporal dead zone - It logs
undefined - It logs
5 - It throws a
SyntaxError
Show answer
It throws a ReferenceError. A let binding is hoisted to the top of its block but stays uninitialized in the temporal dead zone until its declaration is evaluated. Reading x before that declaration hits the dead zone and throws — unlike var, which would simply log undefined.
let and const bindings are hoisted to the top of their block but stay uninitialized — the temporal dead zone — until the declaration is evaluated. Reading x before let x = 5 throws a ReferenceError, unlike var which would log undefined.
JavaScript/prototypes/new-operator
What does new Make() produce? function Make() { this.a = 1; return { a: 2 }; }
Options
{ a: 2 }{ a: 1 }undefined- A new empty object
{}
Show answer
It produces { a: 2 }. new creates a fresh object bound to this, but when a constructor explicitly returns an object, that returned object replaces the freshly-created this. Here Make returns { a: 2 }, so that wins. A returned primitive would instead be ignored and this kept.
new creates a fresh object bound to this, but if the constructor explicitly returns an object, that object replaces the newly-created this. Since Make returns { a: 2 }, that is the result. (A returned primitive would be ignored and this kept.)
JavaScript/objects/optional-chaining
Given const obj = {};, what does obj.foo?.() evaluate to?
Options
undefined- It throws
TypeError: obj.foo is not a function null- An empty object
{}
Show answer
It evaluates to undefined. The optional call ?.() short-circuits when the thing being invoked is null or undefined: rather than throwing a TypeError, the whole expression simply yields undefined. Because obj.foo is undefined here, no call is attempted at all.
The optional call ?.() short-circuits when the thing being called is null or undefined: instead of throwing, the whole expression evaluates to undefined. Since obj.foo is undefined, no call is attempted.
Sources
The official documentation these questions are checked against:
Related interview questions
Job market
See javascript salaries and hiring demand from live job postings.
Practice this for real
CodePrep turns your target job description into an adaptive quiz from a bank of tagged questions, scores your answers, and resurfaces the topics you miss.