Quiz: Spot the Deopt
Test Your V8 Knowledge
Alright, you've made it through hidden classes, inline caches, element kinds, feedback vectors, and deoptimization triggers. Time to put it all together.
For each code example below, your job is to identify the deoptimization trigger -- or determine that the code is V8-friendly. These aren't theoretical puzzles. Every single one comes from real production codebases. Let's see how sharp your V8 intuition has gotten.
Challenge 1: The Shape Shift
function getArea(shape) {
return shape.width * shape.height;
}
const rect = { width: 10, height: 20 };
const square = { width: 10, height: 10, isSquare: true };
for (let i = 0; i < 100000; i++) {
getArea(i % 2 === 0 ? rect : square);
}
Challenge 2: The Array Trap
function sum(arr) {
let total = 0;
for (let i = 0; i < arr.length; i++) {
total += arr[i];
}
return total;
}
const data = new Array(10000);
for (let i = 0; i < 10000; i++) {
data[i] = i;
}
sum(data);
Challenge 3: The Sneaky Coercion
This one's subtle.
function multiply(a, b) {
return a * b;
}
for (let i = 0; i < 50000; i++) {
multiply(i, i + 1);
}
// Later, in a different code path:
multiply(2n, 3n); // BigInt
Challenge 4: The Prototype Pollution
function processItems(items) {
const results = [];
for (let i = 0; i < items.length; i++) {
if (items[i] !== undefined) {
results.push(items[i] * 2);
}
}
return results;
}
const data = [1, 2, 3, 4, 5];
processItems(data);
Challenge 5: The Delete Disaster
By now you should smell this one coming.
function createCache() {
const cache = {};
return {
set(key, value) { cache[key] = value; },
get(key) { return cache[key]; },
remove(key) { delete cache[key]; },
};
}
const c = createCache();
for (let i = 0; i < 1000; i++) {
c.set('key' + i, i);
}
c.remove('key500');
// Now 999 get() calls
for (let i = 0; i < 1000; i++) {
if (i !== 500) c.get('key' + i);
}
Challenge 6: The Feedback Polluter
function add(a, b) {
return a + b;
}
// Warm-up with mixed types during initialization
add("config", "value");
add(true, false);
add(null, undefined);
// Hot path: always integers
for (let i = 0; i < 1000000; i++) {
add(i, i + 1);
}
Challenge 7: The Innocent Refactor
This one's a trick question -- and a good reminder not to over-optimize.
// Version A: Original
function processPoint(p) {
return p.x + p.y;
}
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
const points = Array.from({length: 100000}, (_, i) => new Point(i, i * 2));
let total = 0;
for (const p of points) total += processPoint(p);
// Version B: "Improved" with destructuring
function processPoint({ x, y }) {
return x + y;
}
// ... same Point class and array creation ...
How'd You Do?
7/7: You genuinely understand V8 internals. You'd catch these in code review before they ship.
5-6/7: Strong foundation. Go back and re-read the topics for the ones you missed -- the details matter.
3-4/7: You're getting there. The earlier topics in this module will fill the gaps.
0-2/7: No shame in that -- start from the beginning of this module. These concepts build on each other, and it clicks fast once the mental model lands.
Key Rules
- 1Object shape consistency is the most impactful optimization. Different shapes through the same code path = polymorphic ICs = measurable slowdown.
- 2new Array(n) creates holey arrays permanently. Use push() or Array.from() for packed arrays.
- 3Type pollution from initialization code degrades hot-path optimization. Separate cold and hot functions.
- 4delete transitions objects to dictionary mode, slowing all property access — not just the deleted property.
- 5BigInt, null, undefined, and boolean all create type pollution when mixed with integer arithmetic.
- 6Modern V8 handles many patterns (destructuring, spread, optional chaining) efficiently. Test before assuming a pattern is slow.
- 7When in doubt, use --trace-deopt to see exactly what V8 is doing.