Back to Blog
JavaScriptArraysat()ES2022

JavaScript Array at() Method Guide

Master the JavaScript Array at() method for accessing elements with positive and negative indices.

B
Bootspring Team
Engineering
December 13, 2019
6 min read

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); // undefined

Comparison 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); // 1

Working 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.5

Practical 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(); // 2

Array 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); // undefined

Pagination 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.

Share this article

Help spread the word about Bootspring