The at() method returns the element at a given index, supporting negative indices for accessing from the end. Here's how to use it.
Basic Usage#
1const fruits = ['apple', 'banana', 'cherry', 'date'];
2
3// Positive indices (like bracket notation)
4fruits.at(0); // 'apple'
5fruits.at(1); // 'banana'
6fruits.at(2); // 'cherry'
7
8// Negative indices (from the end)
9fruits.at(-1); // 'date' (last element)
10fruits.at(-2); // 'cherry' (second to last)
11fruits.at(-3); // 'banana'
12fruits.at(-4); // 'apple'
13
14// Out of bounds
15fruits.at(10); // undefined
16fruits.at(-10); // undefinedComparison with Bracket Notation#
1const arr = [1, 2, 3, 4, 5];
2
3// Getting last element
4// Old way
5arr[arr.length - 1]; // 5
6
7// With at()
8arr.at(-1); // 5
9
10// Second to last
11arr[arr.length - 2]; // 4
12arr.at(-2); // 4
13
14// Fifth from end
15arr[arr.length - 5]; // 1
16arr.at(-5); // 1
17
18// Both work for positive indices
19arr[0]; // 1
20arr.at(0); // 1Working with Strings#
1const str = 'Hello, World!';
2
3// at() works on strings too
4str.at(0); // 'H'
5str.at(-1); // '!'
6str.at(-2); // 'd'
7str.at(7); // 'W'
8
9// Useful for getting last character
10const filename = 'document.pdf';
11filename.at(-1); // 'f'
12filename.at(-4); // '.'
13
14// Compare with charAt
15str.charAt(0); // 'H'
16str.charAt(-1); // '' (empty string)
17str.at(-1); // '!' (works!)TypedArrays#
1const buffer = new ArrayBuffer(8);
2const view = new Uint8Array(buffer);
3
4view[0] = 10;
5view[1] = 20;
6view[2] = 30;
7view[7] = 100;
8
9// at() works on TypedArrays
10view.at(0); // 10
11view.at(-1); // 100 (last element)
12view.at(-2); // 0
13
14// All TypedArray types support at()
15const int32 = new Int32Array([100, 200, 300]);
16int32.at(-1); // 300
17
18const float64 = new Float64Array([1.5, 2.5, 3.5]);
19float64.at(-1); // 3.5Practical Examples#
1// Get last item from array
2function getLastItem(array) {
3 return array.at(-1);
4}
5
6const queue = ['task1', 'task2', 'task3'];
7getLastItem(queue); // 'task3'
8
9// Circular array access
10function circularAt(array, index) {
11 const normalizedIndex = ((index % array.length) + array.length) % array.length;
12 return array.at(normalizedIndex);
13}
14
15const days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
16circularAt(days, 0); // 'Mon'
17circularAt(days, 7); // 'Mon' (wraps around)
18circularAt(days, -1); // 'Sun'
19circularAt(days, -8); // 'Sun'
20
21// Stack operations
22class Stack {
23 constructor() {
24 this.items = [];
25 }
26
27 push(item) {
28 this.items.push(item);
29 }
30
31 peek() {
32 return this.items.at(-1);
33 }
34
35 pop() {
36 return this.items.pop();
37 }
38}
39
40const stack = new Stack();
41stack.push(1);
42stack.push(2);
43stack.peek(); // 2Array Slicing Patterns#
1const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
2
3// Get last N elements
4function getLastN(array, n) {
5 return array.slice(-n);
6}
7
8getLastN(numbers, 3); // [8, 9, 10]
9
10// Get element at position from end
11function getFromEnd(array, position) {
12 return array.at(-position);
13}
14
15getFromEnd(numbers, 1); // 10 (last)
16getFromEnd(numbers, 3); // 8 (third from end)
17
18// Remove and return last N
19function popLastN(array, n) {
20 const result = [];
21 for (let i = 0; i < n; i++) {
22 result.unshift(array.at(-1));
23 array.pop();
24 }
25 return result;
26}Method Chaining#
1const data = [
2 { name: 'Alice', score: 85 },
3 { name: 'Bob', score: 92 },
4 { name: 'Charlie', score: 78 },
5];
6
7// Get last sorted item
8const lowestScorer = data
9 .sort((a, b) => a.score - b.score)
10 .at(0);
11// { name: 'Charlie', score: 78 }
12
13const highestScorer = data
14 .sort((a, b) => a.score - b.score)
15 .at(-1);
16// { name: 'Bob', score: 92 }
17
18// Filter and get last
19const passing = [65, 72, 88, 55, 91, 45]
20 .filter((score) => score >= 60)
21 .at(-1);
22// 91
23
24// Map and get first/last
25const names = ['alice', 'bob', 'charlie']
26 .map((name) => name.toUpperCase())
27 .at(-1);
28// 'CHARLIE'Safe Access Pattern#
1// Safe array access with fallback
2function safeAt(array, index, fallback = undefined) {
3 if (!Array.isArray(array) || array.length === 0) {
4 return fallback;
5 }
6 const result = array.at(index);
7 return result !== undefined ? result : fallback;
8}
9
10safeAt([1, 2, 3], -1); // 3
11safeAt([1, 2, 3], 10); // undefined
12safeAt([1, 2, 3], 10, 0); // 0 (fallback)
13safeAt([], -1, 'empty'); // 'empty'
14safeAt(null, 0, 'invalid'); // 'invalid'
15
16// Optional chaining with at()
17const nested = {
18 data: {
19 items: [1, 2, 3],
20 },
21};
22
23nested?.data?.items?.at(-1); // 3
24nested?.missing?.items?.at(-1); // undefinedPagination Helper#
1// Get page items
2function getPage(items, page, pageSize) {
3 const start = (page - 1) * pageSize;
4 const end = start + pageSize;
5 return {
6 items: items.slice(start, end),
7 first: items.slice(start, end).at(0),
8 last: items.slice(start, end).at(-1),
9 total: items.length,
10 pages: Math.ceil(items.length / pageSize),
11 };
12}
13
14const allItems = Array.from({ length: 25 }, (_, i) => `Item ${i + 1}`);
15const page2 = getPage(allItems, 2, 10);
16// {
17// items: ['Item 11', ..., 'Item 20'],
18// first: 'Item 11',
19// last: 'Item 20',
20// total: 25,
21// pages: 3
22// }Ring Buffer#
1class RingBuffer {
2 constructor(size) {
3 this.buffer = new Array(size);
4 this.size = size;
5 this.head = 0;
6 this.count = 0;
7 }
8
9 push(item) {
10 this.buffer[this.head] = item;
11 this.head = (this.head + 1) % this.size;
12 if (this.count < this.size) this.count++;
13 }
14
15 at(index) {
16 if (index < 0) {
17 index = this.count + index;
18 }
19 if (index < 0 || index >= this.count) {
20 return undefined;
21 }
22 const actualIndex = (this.head - this.count + index + this.size) % this.size;
23 return this.buffer[actualIndex];
24 }
25
26 get last() {
27 return this.at(-1);
28 }
29}
30
31const ring = new RingBuffer(3);
32ring.push('a');
33ring.push('b');
34ring.push('c');
35ring.at(-1); // 'c'
36ring.push('d'); // Overwrites 'a'
37ring.at(0); // 'b'
38ring.at(-1); // 'd'Best Practices#
Usage:
✓ Use for negative indexing
✓ Cleaner than length - n
✓ Works on strings too
✓ Safe for method chaining
Benefits:
✓ More readable code
✓ Consistent with other languages
✓ Works with TypedArrays
✓ Returns undefined for out of bounds
Patterns:
✓ Get last element: arr.at(-1)
✓ Get second to last: arr.at(-2)
✓ Safe access with fallback
✓ Method chaining
Avoid:
✗ Using when you need the index
✗ Forgetting undefined return
✗ Overcomplicating simple access
✗ Using with very old browsers
Conclusion#
The at() method provides a clean syntax for accessing array elements with negative indices. Use it to get elements from the end without calculating length - n. It works on arrays, strings, and TypedArrays, and returns undefined for out-of-bounds access rather than throwing an error.