- What does the final statement print?
Answer: 4 30, because the two names reference different functions
When you assign a function to a variable in JavaScript, you're storing a reference to that function object — not the function's name permanently. This question tests whether you understand how variable references work when one variable is reassigned.
Here's what happens step by step: transform is initially declared with function transform(value) { return value + 1; }. Then original = transform copies that reference — both names now point to the same function object (the "add 1" function). Next, transform is reassigned to a brand-new function that multiplies by 10. This reassignment only updates transform; it does not affect original, which still holds its reference to the original "add 1" function. So original(3) returns 4, and transform(3) returns 30, printing 4 30 — making D correct.
A is wrong because reassigning transform doesn't retroactively change original. Once a reference is copied, the two variables are independent. B is wrong because function declarations can be overwritten when they're treated as variables — there's no protection here preventing reassignment. C has the output backwards; it incorrectly claims original sees the new function, when in fact original was assigned before the reassignment happened.
A useful mental model: think of variables as sticky notes pointing to objects in memory. When you write original = transform, you're copying the sticky note's destination, not tying the two notes together forever. Reassigning transform just points its sticky note somewhere new, leaving original untouched.
- What does the final statement print?
Answer: 12, because scale reads its outer factor when called
When you see a function that references a variable from an outer scope, you're being tested on lexical scoping — the rule that a function's variable lookups are determined by where the function was defined, not where it's called from.
scale is defined in the global scope, where factor lives. That means whenever scale runs, it looks up factor in the global environment — not inside whatever function happens to be calling it. By the time apply(scale) is called, factor has been reassigned to 4. So scale(3) computes 3 * 4 = 12, making D correct.
A tempts you into thinking closures "freeze" the value of captured variables at the moment of definition. They don't — closures capture a reference to the variable, not a snapshot. When factor changed to 4, that change is visible to scale.
B is the classic lexical-vs-dynamic scoping trap. apply's local factor = 10 is invisible to scale because scale wasn't defined inside apply. JavaScript uses lexical (static) scoping, not dynamic scoping, so the call stack is irrelevant.
C is a distractor playing on anxiety about naming conflicts. Having two variables named factor in different scopes is perfectly legal in JavaScript — each simply belongs to its own scope chain.
Study tip: Whenever you see a function referencing an outer variable, ask: "Where was this function defined?" That's where JavaScript will look — not where it's being called. This rule applies consistently even across reassignments, which is why tracking a variable's current value at call time matters.
- What does the final statement print?
Answer: 1 2 1, because the returned functions retain separate start bindings
When you see a function returning another function in JavaScript, you're being tested on closures — specifically, whether each returned function gets its own independent copy of the outer variable, or shares one.
Here's what happens: every time makeCounter is called, it creates a brand-new execution context with its own start variable. The inner function "closes over" that specific start — it remembers and mutates its own version. So first and second each hold a separate start initialized to 0.
Walking through console.log(first(), first(), second()): the first first() increments its start from 0 to 1 and returns 1. The second first() increments that same start (now 1) to 2 and returns 2. Then second() increments its own start from 0 to 1 and returns 1. The output is 1 2 1, making D correct.
A is wrong because start isn't reset on each call — the closure persists the variable between calls, which is the whole point of a closure. B tempts you into thinking both functions share one counter, but makeCounter was called twice, producing two independent closures with two separate start bindings — not one shared value. C misreads the order of operations: start is incremented before being returned, so you never get back the original 0.
A useful rule of thumb: every call to an outer function creates a fresh closure environment. If the same function reference is called multiple times, it shares one environment — but two separate calls to the factory produce two entirely independent ones.
- What does this code print, in order?
Answer: 3, followed by TypeError
When you see JavaScript code that mixes function declarations and function expressions, your first instinct should be to think about hoisting — how JavaScript moves certain definitions to the top of their scope before executing any code.
Function declarations (using the function keyword standalone) are fully hoisted, meaning both the name and the body are available before the line where they appear. So when declared(2) runs inside the try block, JavaScript already knows exactly what declared is, and it returns 3. That part executes successfully.
Function expressions (assigning an anonymous function to a variable) behave differently. With var, only the variable declaration is hoisted — not the assignment. At the point expressed(2) is called, JavaScript knows expressed exists as a variable, but its value is still undefined. Trying to call undefined as a function throws a TypeError. The catch block catches this and logs error.name, which is "TypeError". So the output is 3, then TypeError — confirming B is correct.
A is wrong because it assumes expressed is fully available before its assignment, which hoisting does not provide for var-declared function expressions. C is wrong because a ReferenceError would only occur if expressed were completely undeclared — but var does hoist the variable name, just not its value. D is wrong because undefined would be the value of expressed, not what gets logged — attempting to invoke undefined() immediately throws before any return value is produced.
Your study tip: remember the phrase "declarations hoist fully, expressions hoist partially." If you see var + a function expression, the variable exists early but the function doesn't.
- What is printed when this code runs?
Answer: undefined, because the line break completes the return statement
When you see a return statement followed by a line break in JavaScript, you need to think about Automatic Semicolon Insertion (ASI). JavaScript's parser automatically inserts a semicolon after return when the next token appears on a new line — meaning the engine reads it as return;, completing the statement immediately with no value.
That's exactly what happens here. The build function hits return on one line, ASI kicks in, and the function exits returning undefined. The ready function declaration below it is never reached. So typeof value evaluates to "undefined", making A correct.
B is wrong because the ready function is never actually returned. Even though it's defined right after return, ASI separates them — the return statement completes before the parser even sees ready. C is wrong for the same underlying reason: build() never returns the inner function, so there's no way to eventually produce "ok". You'd need something like build()() and a proper return for that to work. D is wrong because no SyntaxError occurs — placing a function declaration after a return statement is syntactically valid JavaScript. The declaration simply becomes unreachable dead code, not an error.
Study tip: Always be suspicious of a return statement with nothing on the same line. ASI turns it into return; automatically, which silently returns undefined — one of JavaScript's sneakiest bugs. When you want to return an object literal or function that spans multiple lines, keep the opening token on the same line as return.
- What does this code print?
Answer: 6 100, because again still names the original function internally
When a function expression includes a named function expression (like function again(n) { ... }), that name — again — is only visible inside the function body itself. It acts as an internal, read-only self-reference, completely separate from any external variable that holds the function.
Here's what happens step by step: sequence is assigned a named function expression called again. Then saved captures that same function. When sequence is reassigned to a new function returning 100, only the variable sequence changes — the original function object still exists, and saved still points to it. When saved(3) runs, it calls the original function. Inside that function, recursion uses again, which always refers to the original function regardless of what sequence holds. So saved(3) computes 3 + 2 + 1 + 0 = 6. Meanwhile, sequence(3) now calls the reassigned function, returning 100. The output is 6 100, making C correct.
A is wrong because reassigning sequence doesn't affect saved, which already holds a reference to the original function — JavaScript passes object references, not names.
B is wrong because sequence was genuinely reassigned; calling sequence(3) after reassignment invokes the new function, not the original one.
D is wrong because again is available during recursion — that's precisely the purpose of named function expressions. The name is bound within the function's own scope automatically.
As a study tip: whenever you see a named function expression, remember the name is scoped to the function body only — it's immune to external reassignment, which makes it reliable for internal recursion.
- Which code should replace the comment so that the program prints
10, does not execute the doubling operation during registration, and does not create a new top-level identifier? Answer: register(function double(n) { return n * 2; });
When working with callback registration, you need to think carefully about when a function executes and what gets stored. The question tests three distinct concepts at once: named function expressions, immediate invocation, and scope pollution.
Option B, register(function double(n) { return n * 2; });, is the correct solution. It passes a function reference — not a function call result — into register, so the doubling logic only runs later when handlers[0](5) is invoked, correctly returning 10. Crucially, the double name is scoped inside the function expression itself, meaning it never appears in the outer scope. No new top-level identifier is created.
Here's where each distractor goes wrong: A does work functionally and would print 10, but it declares double as a top-level function declaration, which violates the constraint about not creating a new top-level identifier — the question explicitly rules this out. C uses an Immediately Invoked Function Expression (IIFE) called with the argument 2, so the function executes during registration and stores the number 4 (not a function) in handlers. Calling handlers[0](5) would then throw a TypeError since 4 is not callable. D also immediately invokes the function, but passes no argument, so n is undefined, and undefined * 2 produces NaN — again storing a non-function in handlers.
A helpful pattern to remember: if you see function(...) {} followed immediately by (), the function executes right there. If the () is absent, you're passing a reference. That distinction is everything when working with callbacks.
- What value is printed?
Answer: 5, after the inner call doubles and the outer call increments
When you see functions being passed around and returned as values, you're looking at first-class functions — a core JavaScript concept. The key skill here is tracing execution carefully, step by step, rather than assuming what the code looks like it does.
Start from the inside out. choose(true) returns the double function (because useDouble is truthy). So run(choose(true), 2) calls double(2), which returns 4. Now the outer call: choose(false) returns the increment function. So run(increment, 4) calls increment(4), which returns 5. That's why A is correct — the inner call doubles 2 to get 4, then the outer call increments 4 to get 5.
B is wrong because it assumes both functions operate on the original value of 2 independently (2×2=4 and 2+1=3, summing to... well, even that math doesn't reach 6). The functions don't run in parallel — the output of the inner run feeds into the outer run.
C is wrong because it misreads choose(false) as also selecting double. Tracing the ternary carefully: useDouble ? double : increment — a false argument returns increment, not double.
D is wrong because choose returning a function is intentional and valid. When you pass that returned function into run, it gets invoked there. Returning a function is not an error.
Study tip: When tracing nested function calls, always resolve the innermost expression first and substitute its return value outward — don't try to read the whole line at once.
- What does this code print?
Answer: local/local, because the local declaration applies throughout report
When you see a function declaration inside another function, the key concept to recall is hoisting. In JavaScript, function declarations (not expressions) are hoisted to the top of their containing scope before any code executes. This means the inner status function inside report is hoisted to the top of report's scope before the first line runs.
This is why C is correct. When report executes, the local status declaration is hoisted, making it the only status visible anywhere inside report. The outer status is completely shadowed. So first = status() calls the local version and captures "local", and the second status() also returns "local". The output is local/local.
A is the most tempting trap — it assumes JavaScript resolves function calls based on where the declaration appears in the source code. That's how many developers intuitively read the code, but it confuses declaration position with hoisting behavior. B falls into the same trap while also incorrectly assuming the outer declaration wins simply because it was defined first globally. D would be reasonable if status were declared with const or let (which create a temporal dead zone), but function declarations are fully hoisted and initialized immediately — no ReferenceError occurs.
A helpful mental rule: whenever you see a function declaration inside a function body, mentally "float" it to the top of that scope before reading the code. If the inner declaration shadows an outer name, it shadows it everywhere inside that scope, not just below the declaration line.
- What does this code print?
Answer: 7, because the returned function is immediately called with 3
When you see chained function calls like (fn)(arg1)(arg2), you're looking at a pattern involving IIFEs (Immediately Invoked Function Expressions) and closures. The key skill is tracing each call step by step rather than trying to read the whole expression at once.
Here's what happens: the outer function (function(base) { ... }) is immediately invoked with 4, so base = 4. That call doesn't return a number — it returns another function: function(amount) { return base + amount; }. Because of closure, this inner function still has access to base. Then, immediately after, that returned function is called with 3, so amount = 3, and the result is 4 + 3 = 7. The variable result stores that final value, making B the correct answer.
A misreads the expression by assuming only the first invocation matters and that 4 is the final output. The first call produces a function, not 4.
C would be correct only if the code stopped after the first invocation — but there's a second (3) chained immediately after, which calls the returned function right away.
D reflects a common fear about unusual syntax, but chaining calls like fn(a)(b) is perfectly valid JavaScript. As long as the first call returns a function, you can invoke that result immediately.
Your strategy: whenever you see (expression)(arg), ask yourself what does the expression evaluate to? If it evaluates to a function, the second (arg) is a valid call on it. Break the expression into sequential steps — left to right — and trace the return value of each.