Array.prototype.copyWithin()

A low-level memmove for arrays, borrowed from the typed-array world. It exists for performance on numeric buffers, and it is almost never the right tool for ordinary application code.

Array methodES2015Live demo
Common call
buf.copyWithin(0, 3)
Returns
the same array, mutated
Replaces
a manual index-copying loop, or splice plus a slice
Watch out
the length is fixed — copying past the end just stops
array.copyWithin(target[, start[, end]])
→ Array

Demo

Live evaluation
Try:
Inputs
itemsnumber[]numbers, comma separated
targetnumberwrite position
startnumberread position
Output
[1, 2, 3, 4, 5].copyWithin(0, 3)
[4, 5, 3, 4, 5]

Watch the LENGTH across every case: it never moves. The first case reads from index 3 to the end and writes that block at index 0, giving [4, 5, 3, 4, 5] — the tail is now duplicated, because the elements it overwrote are simply gone while the ones past the write are left alone. The third case pulls everything up by one and leaves a duplicate of the last element hanging off the end, which is the single most surprising thing about this method: it does not shrink the array the way shift would.

Parameters

NameTypeRequiredDescription
targetnumberyesWhere to start writing. Negative counts from the end. Copying stops when the end of the array is reached.
startnumberno (0)Where to start reading. Negative counts from the end.
endnumberno (length)Where to stop reading, exclusive. Negative counts from the end.

Return value

Array — The SAME array, modified in place. The length is never changed — elements are overwritten, never inserted or removed.

Common patterns

Slide a ring buffer down
The kind of code this method was added for.
buf.copyWithin(0, consumed);
writePos -= consumed;
Duplicate a block in place
No allocation, no intermediate array.
frame.copyWithin(half, 0, half);
What you probably want instead
For ordinary arrays, splice or a spread says what you mean.
const moved = [...items.slice(3), ...items.slice(0, 3)];

Examples

1. Tail to the front
[1, 2, 3, 4, 5].copyWithin(0, 3)
Returns
[4, 5, 3, 4, 5]
2. Bounded by end
[1, 2, 3, 4, 5].copyWithin(0, 3, 4)
Returns
[4, 2, 3, 4, 5]
3. Shift right by one
[1, 2, 3, 4, 5].copyWithin(1, 0)
Returns
[1, 1, 2, 3, 4]
4. Pull up by one
[1, 2, 3].copyWithin(0, 1)
Returns
[2, 3, 3]
5. Length is unchanged
[1, 2, 3].copyWithin(0, 1).length
Returns
3
6. It returns the same array
const a = [1, 2]; a.copyWithin(0, 1) === a
Returns
true

Pitfalls

1. It does not remove anything
The most common misreading. Pulling elements toward the front looks like a shift, but the array keeps its length and the surplus elements stay at the tail as duplicates. If you wanted a shorter array you wanted splice or slice.
Duplicate left behind
[1, 2, 3].copyWithin(0, 1)
[2, 3, 3] // still length 3
Actually shorten it
[1, 2, 3].slice(1)
[2, 3] // length 2
2. It mutates the array it is called on
Not a copy, despite the name. The return value is the very same array, so assigning the result to a new variable gives you two names for one object — and the original is already changed.
Both names, one array
const next = items.copyWithin(0, 1);
next === items
true
Copy first
const next = [...items].copyWithin(0, 1);
items untouched
3. Copying past the end silently stops
There is no error and no growth. A target near the end simply copies fewer elements than you asked for, so an off-by-one shows up as a partial result rather than an exception.
Fewer than expected
[1, 2, 3].copyWithin(2, 0)
[1, 2, 1] // only one element moved
Check the room first
const n = Math.min(count, arr.length - target);
explicit
4. Reaching for it in ordinary code
This exists for typed arrays and performance-critical buffers, where avoiding an allocation matters. In application code it is obscure enough that a reviewer will have to look it up, and slice or splice will be clearer and fast enough.
Obscure
items.copyWithin(0, 1)
needs a trip to the docs
Obvious
items.splice(0, 1)
removes the first element

When to use

Use it
  • Sliding data down a fixed-size buffer without allocating
  • Typed arrays, where this is the idiomatic block move
  • Duplicating a range inside a large array in a hot loop
Reach for something else
  • You want to REMOVE elements → splice, or slice for a copy
  • You want a reordered copy → toSpliced, or a spread of two slices
  • You want to fill a range with one value → fill
  • Ordinary application code → almost anything else reads better

Notes

Complexity
O(n) in the number of elements copied
Return
The same array object, mutated in place; the length never changes
CPython impl
V8: Builtins-array-copywithin.tq
Memory
No allocation at all — that is the entire point of the method
Thread-safe
Single-threaded; overlapping ranges are handled correctly, like memmove

FAQ

Because copyWithin only overwrites. It reads a block and writes it somewhere else in the same array, and every position it did not write keeps whatever it already held. The length is fixed by definition, which is what makes it safe to use on typed arrays.

[1, 2, 3].copyWithin(0, 1);   // [2, 3, 3] — the trailing 3 is the old one

History

ES2015
Added to Array.prototype to mirror the TypedArray method of the same name.