JavaScript Functions Quiz: Closures, this and Scope Practice
Test your JavaScript functions knowledge with 12 questions and three programs on hoisting, default and rest parameters, closures, this, bind and currying.
- Course: JavaScript study plan
- Module: Functions, scope and closures
- Kind: Checkpoint — cleared at 70%
- Reading time: 24 min
- Runtime: Node 16
Checkpoint — Functions, scope and closures is the checkpoint that closes the Functions, scope and closures module: a graded quiz and whole-program exercises, passed at 70%.
Instructions
This checkpoint covers the three ways to define a function and how they hoist, parameters with defaults, rest and spread, lexical scope and the scope chain, closures and their patterns and pitfalls, the five rules for this with call/apply/bind, and higher-order functions — composition, currying and the callback convention.
How it works. Twelve questions and three programs; 70% on the questions and every program accepted clears the module.
Before you start, make sure you can answer:
- Why a function declaration can be called above its line and a
constarrow cannot. - When a default parameter applies, and the difference between rest and spread.
- What a closure captures (variables, not values) and why
for (var …)callbacks all see the last value. - The five
thisrules in precedence order, and the three ways to fix a detached method. - What
bindreturns and why it cannot rebind an arrow. - How
pipeandcomposediffer, and why["1","2"].map(parseInt)fails.
The programs are a counter factory with private state and an audit log, a this-binding tracer that prints which rule decided each call, and a small function-pipeline interpreter built from pipe, curry and once.
Common questions
Why can a function declaration be called before its line but a const arrow cannot?
A function declaration is hoisted with its body, so it is callable anywhere in its scope. A const is hoisted uninitialised and stays in the temporal dead zone until its line runs, so calling the arrow earlier throws a ReferenceError.
What are the three ways to fix a detached method in JavaScript?
Wrap the call in an arrow, () => obj.method(), so the dot call is preserved; bind it with obj.method.bind(obj); or define the method as an arrow class field, whose this is always the instance.
What does bind return in JavaScript?
bind returns a new function with this, and optionally leading arguments, fixed permanently; calling bind again on that function cannot change its this. On an arrow function it has no effect on this, because arrows have none of their own.
Exercises
A counter with an audit log
Write makeCounter() with private value and history and methods inc(by), dec(by), undo() (reverts the last change, returning undid <entry> or nothing to undo), get() and log() (the history entries like +5 -2 space-joined, or (empty)). Read n commands inc <k>, dec <k>, undo, get (prints value=<v>), log (prints log=<entries>).
Example: 7 then inc 5, inc 2, get, undo, get, log, undo →
value=7
undid +2
value=5
log=+5
undid +5Binding precedence
Read three names and make objects a, b, c with those names. With function who() { return this === undefined ? "undefined" : this.name; }, print four lines: bindTwice=<who.bind(a).bind(b)()> (the first bind wins), callOnBound=<who.bind(a).call(c)> (call cannot override), arrowIgnoresBind=<an arrow returning this.name, bound to a, then called> — at the top level of a CommonJS file this is module.exports, whose name is undefined — and newOverridesBind=<new (Named.bind(b))(c.name).name> where function Named(name) { this.name = name; }.
Example: 3 Ada Bo Cy →
bindTwice=Ada
callOnBound=Ada
arrowIgnoresBind=undefined
newOverridesBind=CyA pipeline interpreter
The first line names steps, each name or name:arg, from a registry of step factories: inc, double, add:k, mul:k, and tap (passes the value through and increments a closure-held counter). The second line holds numbers. Build each step by calling its factory with the argument, pipe them, apply the pipeline to every number printing <x> -> <result>, then print tapped=<how many times tap ran>.
Example: inc tap double add:3 tap / 1 2 3 →
1 -> 7
2 -> 9
3 -> 11
tapped=6In this module: Functions, scope and closures
- Declaring functions — declarations, expressions, arrows and parameters
- Lexical scope, the scope chain and hoisting
- Closures — functions that remember
- this — the five binding rules, call, apply and bind
- Higher-order functions — composition, currying and callbacks
- Checkpoint — Functions, scope and closures (this lesson)
← Higher-order functions — composition, currying and callbacks · Object literals — properties, keys, iteration and JSON →