JavaScript Reference

Every method. Every edge case.

Home › Code Snippets › JavaScript › Reference › at()

Part of our complete guide: JavaScript Array Methods →

Array Method · ES2022

Baseline

Array.prototype.at()

Returns the element at a given index. Accepts negative indices to count from the end — the one thing bracket notation can't do.

Last updated: October 2026 📖 8 min read

at() returns the element at a given index. Unlike bracket notation, it accepts negative indices — arr.at(-1) returns the last element. Use it when you need the nth-from-end item without .length - n.

Full definition: Array.prototype.at() returns the element at the specified index. Negative indices count back from the end of the array. Out-of-range indices return undefined instead of throwing. Added in ES2022.

Why at() exists

Before ES2022, getting the last element of an array required one of these workarounds:

// Workaround 1 — verbose
const last = arr[arr.length - 1];

// Workaround 2 — creates a copy
const last = arr.slice(-1)[0];

// Workaround 3 — mutates the array!
const last = arr.pop();

// What at() gives you
const last = arr.at(-1);

The first is verbose. The second allocates an intermediate array. The third destroys the original array. at() solves all three — it's concise, allocation-free, and non-destructive.

The proposal was authored by Shu-yu Guo and Tab Atkins Jr. and shipped in the ES2022 spec. It was designed specifically to mirror how Python, Ruby, and PHP handle negative indexing, so developers coming from those languages would have a familiar tool.

📝

Syntax

array.at(index)
Parameter Type Required Description
index number Yes The index of the element to return. Negative values count from the end. Non-integers are truncated (3.7 → 3).

Return value

Returns the element at the specified index, or undefined if the index is out of range. Never throws.

Index Returns Never throws
Valid positive (0 to length-1)Element✓
Valid negative (-1 to -length)Element✓
Out of range (positive)undefined✓
Out of range (negative)undefined✓
Non-numeric stringundefined✓
NaNundefined✓

10 examples

From basic usage to real-world patterns. Every example is runnable.

Example 1 — Positive index
const fruits = ['apple', 'banana', 'cherry'];
fruits.at(0);   // 'apple'
fruits.at(1);   // 'banana'
fruits.at(2);   // 'cherry'
Example 2 — Negative index (the reason at() exists)
const fruits = ['apple', 'banana', 'cherry'];
fruits.at(-1);  // 'cherry' (last)
fruits.at(-2);  // 'banana' (second-to-last)
fruits.at(-3);  // 'apple' (first)
Example 3 — Compare to bracket notation
const arr = [10, 20, 30];

arr[-1];       // undefined (bracket doesn't support negative)
arr.at(-1);    // 30

arr[arr.length - 1];  // 30 (the old workaround)
arr.at(-1);           // 30 (cleaner)
Example 4 — Out of range (never throws)
const arr = [1, 2, 3];

arr.at(100);    // undefined
arr.at(-100);   // undefined
arr.at(3);      // undefined (3 is out of range for length 3)

// No error. Check for undefined before using:
if (arr.at(100) === undefined) {
  console.log('out of range');
}
Example 5 — Works on strings
const str = 'hello';

str.at(0);    // 'h'
str.at(-1);   // 'o' (last character)

// Handles Unicode correctly
const emoji = '👋🌍';
emoji.at(0);   // '👋' (full emoji, not broken surrogate)
emoji.at(-1);  // '🌍'
Example 6 — Works on TypedArrays
const bytes = new Uint8Array([10, 20, 30]);

bytes.at(0);    // 10
bytes.at(-1);   // 30

// Same behavior as on regular arrays
Example 7 — Chaining
const users = ['alice', 'bob', 'carol'];

// Last user, uppercased
users.at(-1).toUpperCase();
// 'CAROL'

// Second-to-last, sliced
users.at(-2).slice(0, 2);
// 'bo'
Example 8 — In a loop (reverse iteration)
const items = ['a', 'b', 'c'];

for (let i = -1; i >= -items.length; i--) {
  console.log(items.at(i));
}
// c, b, a

// This is what you'd do without at():
for (let i = items.length - 1; i >= 0; i--) {
  console.log(items[i]);
}
Example 9 — Non-integer index (truncated)
const arr = [1, 2, 3, 4];

arr.at(1.9);    // 2 (truncates to 1)
arr.at(0.5);    // 1 (truncates to 0)
arr.at(-1.9);   // 4 (truncates to -1)
Example 10 — Real-world: getting the last item safely
// Before at()
function getLastItem(items) {
  if (!items || items.length === 0) return null;
  return items[items.length - 1];
}

// After at() — still check for undefined, but cleaner
function getLastItem(items) {
  return items?.at(-1) ?? null;
}

getLastItem([1, 2, 3]);  // 3
getLastItem([]);          // null
getLastItem(null);        // null
getLastItem(undefined);   // null

🔬 Edge cases

The cases most tutorials skip. These are what cause production bugs.

Empty array
[].at(0);    // undefined
[].at(-1);   // undefined
// Never throws
Negative index beyond length
const arr = [1, 2, 3];

arr.at(-4);   // undefined (beyond start)
arr.at(-5);   // undefined

// The -1 index maps to length - 1 = 2
// The -3 index maps to length - 3 = 0
// Anything beyond -3 is undefined
Sparse arrays
const sparse = [1, , 3];   // note the hole at index 1

sparse.at(0);   // 1
sparse.at(1);   // undefined (hole)
sparse.at(2);   // 3

// Same behavior as bracket notation
sparse[1];      // undefined
at() on strings vs arrays
'hello'.at(0);   // 'h'  (string)
['h','e'].at(0); // 'h'  (array)

// Both work. at() is on both String.prototype
// and Array.prototype.
Array-like objects (arguments, NodeList)
function f() {
  arguments.at(0);   // ❌ TypeError: arguments.at is not a function
}

// Convert first
Array.from(arguments).at(0);   // ✅

// NodeList similarly
Array.from(document.querySelectorAll('p')).at(0);
at() on null / undefined
null.at(0);       // ❌ TypeError
undefined.at(0);  // ❌ TypeError

// Use optional chaining
someArray?.at(0); // ✅ returns undefined if null/undefined
at() vs bracket for existence of undefined values
const arr = [undefined, 1, 2];

arr.at(0);      // undefined
arr[0];         // undefined

// Both return undefined, but the element EXISTS
// Distinguish with: 0 in arr → true
-0 vs 0
const arr = [10, 20, 30];

arr.at(0);   // 10
arr.at(-0);  // 10 (-0 === 0 in JavaScript)

// Both access the first element

⚡ Performance

Operation Time complexity Space Notes
at(n)O(1)O(1)Same as bracket
at(-n)O(1)O(1)Subtracts from length
arr[arr.length - 1]O(1)O(1)Equivalent speed
arr.slice(-1)[0]O(n)O(n)Allocates a copy
arr.pop()O(1)O(1)Mutates the array

In practice: at() vs bracket performance is indistinguishable. Modern JS engines inline at() calls. Choose at() for clarity (especially with negative indices), not for speed.

🎯 at() vs bracket vs slice() vs pop()

Method Returns Negative index Mutates Use when
at() Element or undefined ✓ No You need a specific index, possibly from the end
arr[n] Element or undefined ✗ No You need a known positive index
slice() New array ✓ No You need a range, not one item
pop() Last element N/A Yes You want to remove and return the last item
find() Element or undefined N/A No You need to search by value, not index

🌐 Browser support

Baseline since March 2022. Fully available in all modern browsers.

Environment Version Support
Chrome92+✓
Firefox90+✓
Safari15.4+✓
Edge92+✓
Node.js16.6+✓
DenoAll✓
IE 11—✗ No polyfill

Need IE11 support? Skip at() and use arr[arr.length - 1]. A polyfill would add weight for a dead browser.

⚠️ Common mistakes

❓ Frequently asked questions

What does Array.at() do in JavaScript?

Array.at(index) returns the element at the given index. Unlike bracket notation, it accepts negative indices where -1 returns the last element, -2 the second-to-last, and so on. Returns undefined if the index is out of range.

What is the difference between at() and bracket notation?

at() accepts negative indices to count from the end; bracket notation does not. arr[-1] returns undefined, while arr.at(-1) returns the last element. For non-negative indices, they behave identically.

When was Array.at() added to JavaScript?

Array.prototype.at() was added in ES2022. It is available in all modern browsers since early 2022, including Chrome 92+, Firefox 90+, Safari 15.4+, and Node.js 16.6+.

Does at() work on strings?

Yes. String.prototype.at() was added at the same time. 'hello'.at(-1) returns 'o'. It handles Unicode code points correctly, unlike bracket notation which can split surrogate pairs.

Is at() faster than bracket notation?

No. Both are O(1) and perform identically for non-negative indices. at() has a small overhead of a function call plus a range check, but this is negligible in practice. Use whichever is clearer.

What does at() return for out-of-range indices?

undefined. It never throws. arr.at(100) on a 5-element array returns undefined. arr.at(-100) also returns undefined.

Can I use at() on array-like objects?

Not directly. at() must be called on an actual Array or TypedArray. For array-like objects (like arguments or NodeList), convert first with Array.from() or the spread operator.

What is the difference between at() and slice()?

at() returns a single element (or undefined). slice() returns a new array containing multiple elements. Use at() for one item, slice() for a range.

🔗 Related methods

🌐 External resources

← Back
JavaScript Reference
Next →
All Array Methods
← All JavaScript Reference