Skip to the solution
HardDSA8 min read

How does V8 Array copy-on-write optimization work for toSorted/toReversed/toSpliced/with?

224 views

The problem

Question presented to candidate: "V8 has a well-known copy-on-write optimization for JavaScript arrays. Do the new ES2023 methods toSorted, toReversed, toSpliced, and with take advantage of that COW sharing to make their copy lazy, or do they always eagerly copy? Show me, do not just tell me."

What a strong answer should cover:

  • V8 genuinely has a copy-on-write (COW) backing-store optimization for arrays: when an array's element storage is marked COW (most commonly, a freshly-evaluated array literal), a shallow clone via slice() or spread [...arr] can share the exact same backing FixedArray instead of allocating a new one β€” verified directly by inspecting V8 internals.
  • The four ES2023 change-array-by-copy methods do NOT participate in that lazy sharing. Each one allocates a brand-new, non-COW backing store immediately at call time, verified directly β€” even with(index, value), which only changes a single element, does not share the other unchanged elements.
  • This makes sense once the two questions are separated: COW sharing is about WHEN a copy physically happens for methods that produce an array that starts out identical to the source. toSorted/toReversed/toSpliced/with all produce arrays that are already structurally different the moment they return, so there is nothing identical left to lazily share.
  • These four methods should be budgeted as a genuine O(n) allocation on every call, confirmed by direct benchmark: with() on a 20,000-element array costs essentially the same as a manual spread-then-assign copy.
  • Contrast with slice()/spread, which really can be near-free when the source is COW-eligible, verified via a real backing-store-address comparison before and after the call.

Clarifying questions expected:

  • "Are we talking about V8 specifically, or does the ECMAScript spec itself mandate a particular allocation strategy?" β€” the spec only mandates the observable result (an independent array); COW sharing is a pure V8 implementation detail other engines are free to implement differently.
  • "Does the source array's own origin matter β€” a literal versus something built with Array.from or map?" β€” worth naming that COW eligibility in V8 is tied to how the source array itself was created, not a universal property of every array.

Code / implementation expected: Yes β€” direct inspection of V8's internal backing-store pointers via --allow-natives-syntax and %DebugPrint, not a description from memory, plus a real benchmark comparing native with() against a manual copy.

  • v8
  • array
  • performance

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

8 min read Β· 8 sections

Run the code

Edit the code and run it here. Each console line with an expected value becomes a test.

JavaScriptCorrectness + real benchmark: none of the four methods mutate the source, and with() costs the same as a manual copy (run directly)
JavaScriptReference: direct V8 internals proof via --allow-natives-syntax and %DebugPrint (run with: node --allow-natives-syntax file.js -- not runnable in the browser playground, this flag is Node/V8-CLI-only)
function backingStoreOf(label, arr) {
  console.log(`
---- ${label} ----`);
  eval("%DebugPrint(arr)"); // prints the real internal layout, including the backing FixedArray's address
}

const literalSrc = [3, 1, 2];
backingStoreOf("source (array literal)", literalSrc);
backingStoreOf("toSorted() result", literalSrc.toSorted());

const literalSrc2 = [1, 2, 3];
backingStoreOf("source (array literal)", literalSrc2);
backingStoreOf("slice() result", literalSrc2.slice());

// Run this file with: node --allow-natives-syntax this-file.js
// Then compare the "elements:" line's 0x... address and the [COW] tag
// between each "source" print and its corresponding result print.

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 159 of 165 in JavaScript

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

Up nextHard

What are WeakMap and WeakSet?

Continue