JSE Certified Entry-Level JavaScript Programmer study materials
JSE Certified Entry-Level JavaScript Programmer study resources

JSE Certified Entry-Level JavaScript Programmer common mistakes

JSE Certified Entry-Level JavaScript Programmer · Understand the traps and how to avoid them.

Mistake 1

Treating `var` as block-scoped inside an `if` or `for` block, then logging the variable after the block and expecting `ReferenceError`.

Candidates learn let/const first and assume all declarations are block-scoped; var is function-scoped and hoisted with value undefined, so the access succeeds and returns undefined or a leftover loop value.

What to do instead

Memorise the rule: var is scoped to the nearest function (or global), let/const to the nearest block. Trace one example by hand where a var declared in a for loop is read after the loop, and one where let is read after the block to see the ReferenceError.

Mistake 2

Predicting `typeof null` returns `"null"`, or expecting `typeof` on an undeclared identifier to throw.

typeof null returning "object" is a historical bug in the language that candidates expect to be fixed, and typeof is the one operator that is safe on undeclared names, which is counterintuitive.

What to do instead

Memorise the two exceptions explicitly: typeof null === "object" and typeof undeclaredName === "undefined" without error. Use value === null to test for null, never typeof.

Mistake 3

Assuming `==` and `===` behave the same for `0`, `""`, `null`, and `undefined`, and answering that `null == undefined` is `false`.

Candidates conflate == with truthiness rules. Loose equality has its own coercion table: null == undefined is true, but null == 0 is false, and 0 == "" is true.

What to do instead

Learn the loose-equality table as a small set of facts rather than a general rule: null/undefined are loosely equal only to each other; NaN equals nothing including itself; strings coerce to numbers against numbers. Default to === in code and reserve == questions for the table.

Mistake 4

Expecting `const` to make an array or object immutable, and being surprised that `const arr = [1]; arr.push(2)` works.

Candidates read const as "constant value" rather than "constant binding". The binding cannot be reassigned, but the referenced object can still be mutated.

What to do instead

State the rule as: const prevents reassignment of the identifier, not mutation of the value. Only Object.freeze (shallow) prevents mutation. Practise distinguishing arr = [] (throws) from arr.push() (allowed).

Mistake 5

Using `break` inside `forEach` to stop iteration, or expecting `return` inside a `forEach` callback to exit the enclosing function.

Candidates transfer loop habits to array methods. forEach ignores break (it is a syntax error in the callback) and return only exits that one callback invocation, so iteration continues.

What to do instead

Remember forEach always visits every element unless it throws. To stop early use a for/for...of loop with break, or some/every/find which short-circuit on a boolean or match condition.

Mistake 6

Writing a function declaration and a function expression and assuming both are fully hoisted and callable before their line.

Function declarations are hoisted with their body, but var f = function(){} hoists only the var as undefined, so calling it early throws TypeError: f is not a function. Candidates generalise from declarations.

What to do instead

Classify declarations versus expressions before answering. Declaration: callable above its definition. var expression: undefined until assignment. let/const expression: temporal dead zone, ReferenceError.

Mistake 7

Predicting `[10, 1, 2].sort()` gives `[1, 2, 10]`, and `[1, 2, 10].sort()` gives a numeric order.

Candidates assume sort is numeric. The default comparator converts elements to strings and compares UTF-16 code units, so "10" sorts before "2".

What to do instead

Memorise that sort() without a comparator is lexicographic. Always supply (a, b) => a - b for numbers. Note sort mutates the array and returns the same reference.

Mistake 8

Believing `try/catch` catches errors thrown inside a later `setTimeout` callback or inside a rejected promise that is not awaited.

Candidates treat try/catch as global. It only catches synchronous throws on the current call stack; asynchronous callbacks run later on a fresh stack, so the catch block has already finished.

What to do instead

Match the mechanism to the timing: synchronous code uses try/catch; promises use .catch() or await inside try; callbacks need their own try/catch inside the callback. Recognise that an unhandled rejection is not caught by an outer try.

Mistake 9

Calling `addEventListener` on an element selected before the DOM is parsed, or selecting with `getElementById` before the script runs, and getting `null`.

A script in <head> executes before the body elements exist, so the query returns null and the subsequent property access throws TypeError. Candidates assume the element is available because it appears in the HTML.

What to do instead

Place scripts before </body>, add the defer attribute, or wrap initialisation in DOMContentLoaded. Always check the selection result before binding listeners.

Mistake 10

Mixing up `event.target` and `event.currentTarget` in a delegated handler, or forgetting `preventDefault` versus `stopPropagation`.

Both properties exist on every event and point to the same element when the listener is on the target itself. Candidates also conflate cancelling the default browser action with stopping the event from bubbling.

What to do instead

Fix the definitions: target is the element that dispatched the event; currentTarget is the element whose listener is running. preventDefault cancels the browser default; stopPropagation halts bubbling. Use currentTarget in delegated handlers.