Prediction Beats Copying When You're Learning JavaScript
Prediction beats copying when you're learning JavaScript because prediction makes a private mental model visible. Copying working code can produce the right screen, the right console output, or the right green tests without forcing the learner to explain what the program is about to do.
A prediction is less forgiving. Before the runtime answers, the learner has to commit:
I think this value is an array.
I think this object still has three keys.
I think the timer logs last.
I think this function returns undefined.
That commitment is the useful part. It turns learning from recognition into a testable model.
Copying Produces Recognition
Copying feels productive because the feedback is immediate. The code runs. The error disappears. The solution looks familiar. That is not worthless. A learner can absorb naming, formatting, method order, and small patterns by copying good examples.
But copying also lets the hard question slide past:
Could you have predicted this result before seeing it?
If the answer is no, the copied code has not become executable knowledge yet. It is still a shape the learner recognizes.
That distinction matters most in JavaScript because so many beginner mistakes are not syntax mistakes. The code is valid. The program runs. The surprise is in the value.
Prediction Creates A Testable Model
Consider this small object-method example:
const stock = {
apples: 42,
bananas: 0,
cherries: 15,
};
const entries = Object.entries(stock);
const filtered = entries.filter(([item, qty]) => qty > 0);
const rebuilt = Object.fromEntries(filtered);
console.log(entries[0]);
console.log(filtered);
console.log(rebuilt);
A learner can copy the final pattern:
Object.fromEntries(Object.entries(stock).filter(([item, qty]) => qty > 0));
That may work. It may even pass the test. But the important model lives between the calls:
Object.entries(stock) becomes pairs.
filter keeps pairs, not plain values.
Object.fromEntries turns the remaining pairs back into an object.
The output makes the model checkable:
["apples", 42]
[["apples", 42], ["cherries", 15]]
{ "apples": 42, "cherries": 15 }
If the learner predicted filtered as [42, 15], the problem is not that they "do not know Object.entries." The problem is more precise: they lost the pair shape. That is exactly the kind of mistake a good prediction can expose.
The Error Is Smaller When The Prediction Is Specific
Bad practice asks for a vibe:
Do you understand object methods?
Better practice asks for a value:
What is the first entry?
What shape does filter keep?
How many keys are in the rebuilt object?
Now a wrong answer has a location. The learner is not vaguely "bad at objects." They made one wrong claim about one step.
That is why prediction pairs so well with debugging. A bug is often a failed prediction that nobody wrote down. The program did something different from the story in the developer's head. When learners practice writing the story first, the mismatch becomes easier to find.
This is related to deliberate logging, but it is not the same habit. Logging inspects what happened. Prediction commits to what should happen. The strongest loop uses both: predict, run, inspect, revise.
Predict And Run In JS Exercises
JS Exercises uses "Predict and Run" stages because they make learners slow down at the exact moment most people want to rush.
In Working with Data: Object Methods, prediction stages ask learners to track the shape changes:
- Object.keys and Object.values asks for the numeric values that survive a filter.
- Object.entries asks for the first
[key, value]pair. - Object.fromEntries asks for both the filtered pairs and the rebuilt object.
- Spreading Objects asks what happens to a nested scores array after a shallow copy is mutated.
Those are not trivia questions. They train the learner to preserve data shape in their head.
In Working with Data: JSON, the same pattern trains the boundary between JavaScript values and JSON text:
- JSON.stringify asks learners to predict that the result is a string.
- JSON.parse asks whether a parsed
scoresproperty is really an array again. - JSON Gotchas asks what survives when functions,
undefined, arrays, and dates pass through JSON.
That last one is a perfect example of why copying is not enough:
const value = {
name: "Ada",
greet() {
return "hi";
},
missing: undefined,
scores: [1, undefined, 3],
};
console.log(JSON.stringify(value));
The output is:
{"name":"Ada","scores":[1,null,3]}
The function disappeared. The object property with undefined disappeared. The array position stayed, but its value became null. A learner who predicts that output has a real model of JSON compatibility. A learner who only copies JSON.stringify(value) may not.
In Working with Data: Destructuring and Spread, prediction stages put pressure on position, property names, rest values, and copying:
- Array Destructuring checks whether a skipped position is really skipped.
- Object Destructuring checks how renamed properties and parameter destructuring behave.
- Rest in Destructuring checks what remains after named properties are pulled out.
- Array Spread checks whether mutating the copy changes the original.
These stages are deliberately small. The point is not to make JavaScript feel like paperwork. The point is to isolate one moving part so the learner can feel the difference between "I saw this syntax" and "I can execute this syntax mentally."
Async Code Makes Prediction Non-Negotiable
Async JavaScript is where copying becomes especially deceptive. A learner can copy a Promise chain or an async function and still have no idea why one line logs before another.
This code is short, but it exposes the whole problem:
console.log("sync 1");
queueMicrotask(() => {
console.log("microtask");
});
Promise.resolve().then(() => {
console.log("promise");
});
setTimeout(() => {
console.log("timeout");
}, 0);
console.log("sync 2");
The output is:
sync 1
sync 2
microtask
promise
timeout
The learner needs a model, not a memorized answer:
Synchronous code runs first.
Microtasks run after the stack empties.
Microtasks keep their queue order.
The timer callback is a task, so it waits.
That is why The Event Loop includes a setTimeout output prediction, and Microtasks and the Microtask Queue ends with a full output-order prediction. If learners do not predict async order before running it, the console becomes a magic trick. Interesting, but not very educational.
Standalone Exercises Use The Same Pressure
The same idea shows up outside the course stages.
String Positions asks learners to predict characters from zero-based indexes before they write any new string code. Return vs Log asks them to separate what a human sees in the console from what the caller receives. Scope Chain Lookup asks them to follow where JavaScript finds a variable name.
In each case, the answer is not a full program. It is a prediction variable. That matters.
The learner cannot hide behind "the code kind of works." They have to say what the value is. Then the tests check that claim.
Prediction Is Not Guessing
Guessing is random. Prediction is constrained by the code.
A useful prediction habit looks like this:
- Read the code without running it.
- Write the expected value, shape, or output order.
- Run the code.
- Compare the result to the prediction.
- Explain the first place your model split from reality.
- Change one input and predict again.
That last step matters. If the learner only memorizes the answer for one example, the model stays brittle. Changing one value tests whether the rule transferred.
For example, after predicting Object.entries(stock), change bananas from 0 to 6. The learner should be able to predict that bananas now survives the filter. If they cannot, they learned the old output, not the rule.
Copying Still Has A Place
Copying is not the villain. Copying before thinking is the problem.
There is a productive way to copy:
- Predict what the example will do.
- Copy it and run it.
- Mark the line that surprised you.
- Delete the code and rebuild it from memory.
- Change one requirement and adapt the pattern.
Now copying becomes study instead of substitution. The learner gets the benefit of a working model, but they still have to do the mental work that makes the model portable.
That is the difference between "I copied an example of Object.fromEntries" and "I know when object data becomes pairs, when it stays pairs, and when it becomes an object again."
One of those survives the next problem. The other survives until the tab closes.
Key Takeaways
- Copying working JavaScript can build familiarity, but it does not prove the learner can execute the code mentally.
- Prediction makes the learner's mental model testable before the runtime supplies the answer.
- Wrong predictions are valuable when they are specific: value shape, mutation, return value, scope lookup, or output order.
- JS Exercises uses Predict and Run stages to train data shape, JSON boundaries, destructuring, spread, and async execution order.
- Copy after prediction, then change the example. That is how copied code becomes transferable knowledge.