From the ai augmented javascript sample test
Why does AI sometimes suggest array.push() inside a map callback?
The item shows a candidate an AI-generated JavaScript snippet
where the assistant has reached for array.push() inside an
Array.prototype.map callback to build up a derived list, and
asks the candidate to identify what is wrong with the snippet
and produce the idiomatic fix. The question probes the
collaboration loop that defines AI-augmented JavaScript work:
the candidate is not asked to author the code from scratch,
but to recognize a recurring class of AI-generated mistake and
correct it without breaking the surrounding contract.
What this question tests
The concept under test is the distinction between mutation
and transformation in array workflows, and how AI assistants
sometimes blend the two in ways that violate idiomatic
JavaScript expectations. Array.prototype.map is defined by
the ECMAScript specification as a transformation: it returns a
new array whose elements are the result of calling the callback
on each element of the source. The callback’s return value is
what populates the output array. When an AI assistant generates
code that uses push inside a map callback, it is layering an
imperative side effect on top of a functional construct, and
the result is usually a buggy hybrid: either two arrays are
populated (the original map result and a side-band array
built up by push), or the map return value is discarded and
the side-band array is the real output, in which case forEach
or a plain for loop would have been the right primitive to
begin with.
The question targets candidates who are doing real AI-collaboration work — accepting suggestions, modifying them, spotting class-of-bug patterns rather than one-off typos. It distinguishes candidates who treat AI output as a starting draft to be reviewed against language semantics from candidates who paste accepted suggestions directly into production.
Why this is the right answer
The correct fix is to use map for transformations and let the
callback’s return value populate the output array. No imperative
push is needed:
// AI-generated, buggy: push inside map
const doubled = [];
numbers.map((n) => {
doubled.push(n * 2);
});
// Idiomatic fix: let map's return value be the output
const doubled = numbers.map((n) => n * 2);
If the work genuinely requires accumulation with branching —
say, “double evens, drop odds” — the right primitive is
filter chained with map, or a single reduce:
const doubledEvens = numbers
.filter((n) => n % 2 === 0)
.map((n) => n * 2);
// Or a single pass via reduce
const doubledEvens = numbers.reduce((acc, n) => {
if (n % 2 === 0) acc.push(n * 2);
return acc;
}, []);
The reduce form does use push, but push lives inside an
explicit accumulator pattern where mutation is local to the
fold and the input array is untouched. This is the structural
difference that separates idiomatic from buggy AI suggestions:
mutation is fine when it is contained inside a deliberately
imperative construct, and broken when it escapes into a
construct (like map) whose contract is purely functional.
What the wrong answers reveal
The plausible wrong options each map onto a different misconception about AI-augmented JavaScript work:
- “The snippet is correct because
pushreturns the new length, whichmapcollects.” This option encodes a fundamental misreading of whatmapdoes.mapcollects the return values of the callback, but if the callback returns the result ofpush(a length number), the output array becomes a list of integers, not the doubled values. Picking this option suggests the candidate has not internalized the callback-return-value contract. - “The snippet is correct;
mapis just a fancyforEach.” This conflates two array methods that have different contracts.forEachis for side effects;mapis for transformation. Treating them as interchangeable is a hallmark of candidates who haven’t read the spec and are pattern-matching AI output. - “Replace
mapwithforEachand keep thepush.” This is technically functional but misses the idiomatic point.forEachwithpushis what an imperative loop looks like in JavaScript; the senior-level fix usesmapdirectly so the transformation is declarative and the output is bound to a single expression.
How the sample test scores you
In the AIEH 5-question AI-Augmented JavaScript sample, this item contributes one of five datapoints aggregated into a single ai_js_proficiency score via the W3.2 normalize-by-count threshold. Binary scoring per item: 5 for the correct option, 1 for any of the three wrong options. With 5 binary items, the average ranges 1–5 and the level threshold maps avg ≤ 2 to low, ≤ 4 to mid, > 4 to high.
Data Notice: Sample-test results are directional indicators only. A 5-question sample can’t reliably distinguish between “spots class-of-bug patterns from AI assistants” and “got lucky on these specific items”; for a verified Skills Passport credential, take the full 50-question assessment.
The full assessment probes prompt-engineering with code, AI-output
review, refactoring AI suggestions, and the specific JavaScript
gotchas (closure scope, this binding, equality coercion, async
control flow) at depth. See the scoring methodology
for how AI-Augmented JavaScript scores map onto the AIEH 300–850
Skills Passport scale.
Related concepts
- Pure functions and referential transparency. A
mapcallback that pushes to an outer array introduces a side effect that breaks referential transparency. Functional patterns that avoid side effects are easier for both humans and AI assistants to reason about, and they compose with promise chains and async iteration without surprises. - Immutability in React and Redux. The
push-inside-mappattern is especially harmful in React state updates, where mutating the previous state array prevents React from detecting that a re-render is needed. AI assistants occasionally generate this anti-pattern when prompted with React state-update tasks; reviewers should flag it the same way they flag mutation in any other reducer. - The
for...ofescape hatch. When the work genuinely needs imperative accumulation with early termination or multiple side outputs,for...ofis the language-level primitive the spec offers. Reaching for it is sometimes the right call; the bug is reaching for it implicitly viapushinsidemaprather than explicitly via a loop.
For the broader AI-Augmented JavaScript lineup including the full 50-question assessment, see the tests catalog and the interview question design guide for how to construct similar items in your own hiring loops. Hiring managers can also explore the AI fluency in hiring write-up for the broader context.
Sources
- Ecma International. (2024). ECMAScript 2024 Language
Specification (ECMA-262, 15th edition). — Section 23.1.3.18
defines
Array.prototype.map. https://tc39.es/ecma262/ - MDN Contributors. (2024). Array.prototype.map() — JavaScript Reference. Mozilla Developer Network. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
- MDN Contributors. (2024). Array.prototype.forEach() — JavaScript Reference. Mozilla Developer Network. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
- Simpson, K. (2020). You Don’t Know JS Yet: Scope & Closures (2nd ed.). — Chapter 2 on lexical scope underlies the mutation-vs-transformation distinction in functional array methods.