Array.prototype.at()

Exists for one reason: bracket notation cannot do negative indices. arr[-1] looks up a PROPERTY named "-1" and quietly gives undefined.

Array methodES2022Live demo
Common call
items.at(-1)
Returns
the element, or undefined when out of range
Replaces
items[items.length - 1]
Watch out
out of range gives undefined, not an error
array.at(indexindex — Position to read. Negative counts from the end, so -1 is the last element. A fractional index is truncated toward zero.type: number · required)
→ any

Demo

Live evaluation
Try:
Inputs
itemsnumber[]numbers, comma separated
indexnumberindex (try -1)
Output
[1, 2, 3, 4].at(-1)
4

Positive indices behave exactly like bracket notation. Negative indices are the point: -1 is the last element, -2 the one before it, and so on. An index outside the array in either direction gives undefined rather than throwing, which is the same behaviour bracket notation has — so at() changes what you can express, not how failure is reported.

Parameters

NameTypeRequiredDescription
indexnumberyesPosition to read. Negative counts from the end, so -1 is the last element. A fractional index is truncated toward zero.

Return value

any — The element at the index, counting from the end when the index is negative. undefined when the index is out of range.

Common patterns

Take the last element
The reason the method was added.
const last = items.at(-1);
Read from the end without arithmetic
Replaces the length-minus-n idiom.
const secondLast = items.at(-2);
Works on strings too
String.prototype.at has the same signature.
const lastChar = 'hello'.at(-1);

Examples

1. Last element
[1, 2, 3].at(-1)
Returns
3
2. First element
[1, 2, 3].at(0)
Returns
1
3. Bracket fails
[1, 2, 3][-1]
Returns
undefined
4. Out of range
[1, 2, 3].at(99)
Returns
undefined
5. The old idiom
const a = [1, 2, 3]; a[a.length - 1]
Returns
3
6. Strings too
'hello'.at(-1)
Returns
'o'

Pitfalls

1. arr[-1] is not an error, it is undefined
Bracket notation treats -1 as a property NAME, not an index — and the property does not exist, so you get undefined. Nothing throws, so the bug reaches production as a missing value rather than a crash.
Silently undefined
[1, 2, 3][-1]
undefined
Use at()
[1, 2, 3].at(-1)
3
2. Out of range gives undefined, not an error
Like bracket notation, at() never throws for a bad index. Chaining a property access straight onto the result is what actually fails, one line later.
Fails downstream
items.at(99).name
TypeError: Cannot read properties of undefined
Optional chaining
items.at(99)?.name
undefined
3. ES2022 and newer only
Not available in older runtimes. The portable equivalent is the length-minus-n idiom, which is why so much existing code still uses it.
Missing method
items.at(-1)
TypeError: items.at is not a function
Old idiom
items[items.length - 1]
works everywhere

When to use

Use it
  • Reading the last or second-to-last element
  • Any index computed relative to the end
  • Replacing the arr[arr.length - 1] idiom for readability
Reach for something else
  • Plain forward indexing → bracket notation is shorter
  • Runtimes older than ES2022 → arr[arr.length - 1]
  • You want to WRITE to the position → at() is read-only

Notes

Complexity
O(1)
Return
The element or undefined; the array is never modified
CPython impl
V8: Builtins-array-at.tq
Memory
No allocation
Thread-safe
Single-threaded; the source is only read

FAQ

Because arrays are objects and bracket notation with -1 looks up a property literally named "-1". No such property exists, so you get undefined rather than the last element. at() interprets the number as an index and counts from the end.

[1, 2, 3][-1]     // undefined
[1, 2, 3].at(-1)  // 3

History

ES2022
at() added to Array, String and the typed arrays, specifically to support negative indexing.