JavaScript Arrays Explained: Creation, Access, and Common Mistakes
Every app you use daily — your music player, your shopping cart, your Instagram feed — is secretly just lists of things displayed in a particular order. A playlist is a list of songs. A cart is a list of products. A feed is a list of posts. JavaScript needs a way to store and manage those lists, and that is exactly what arrays do. Without arrays, you would have to create a separate variable for every single item — imagine writing song1, song2, song3 all the way to song500. That is not programming, that is torture.
Arrays solve the 'I have many related things and I need to work with them together' problem. They let you store an unlimited number of values under one variable name, access any item instantly by its position, add or remove items on the fly, and loop through every item without writing repetitive code. They are the single most used data structure in JavaScript, and you will reach for them constantly.
By the end of this article you will know how to create an array, read and change its values, add and remove items, loop through every element, and avoid the three mistakes that trip up almost every beginner. You will also know the answers to the array questions that show up in almost every junior JavaScript interview.
Creating an Array and Reading Values From It
You create an array using square brackets [] with values separated by commas. That is the whole syntax. The values inside are called elements, and they can be any type — numbers, strings, booleans, even other arrays.
The critical thing to burn into your memory right now: arrays in JavaScript are zero-indexed. The first item lives at position 0, not position 1. This trips up every beginner at least once. Think of it like floors in a European building — the ground floor is floor 0, the next one up is floor 1.
To read a specific element you write the array name followed by the index (position number) inside square brackets — myArray[0] gives you the first item. You can also check how many items are in an array using the .length property, which always tells you the actual count (not the last index — that is always length - 1).
Arrays can hold mixed types, but in practice you will almost always store the same kind of data in one array. A list of usernames, a list of prices, a list of temperatures — keeping things consistent makes your code far easier to reason about.
// Create an array of fruit names using square bracket syntax const shoppingBasket = ['apple', 'banana', 'cherry', 'mango', 'kiwi']; // Arrays are ZERO-indexed — the first item is at index 0, not 1 console.log(shoppingBasket[0]); // 'apple' — first item console.log(shoppingBasket[1]); // 'banana' — second item console.log(shoppingBasket[4]); // 'kiwi' — fifth (last) item // .length tells you how many items are in the array console.log(shoppingBasket.length); // 5 // The LAST item is always at index: length - 1 // This works even if you don't know how long the array is console.log(shoppingBasket[shoppingBasket.length - 1]); // 'kiwi' // What happens if you ask for an index that doesn't exist? console.log(shoppingBasket[10]); // undefined — no crash, just undefined // Arrays can hold mixed types (though you'll rarely need this) const mixedBag = ['hello', 42, true, null]; console.log(mixedBag[2]); // true
banana
kiwi
5
kiwi
undefined
true
Changing, Adding, and Removing Items in an Array
An array is not read-only — you can update existing items, push new ones onto the end, or remove items from either end. This is where arrays start to feel alive.
To update an item, simply assign a new value to its index: basket[0] = 'grape' replaces whatever was at position 0 with 'grape'. The array length stays the same.
To add items to the end of an array, use .push(). It is the most common way to grow an array — think of it like tossing something into the back of a queue. You can push one item or several at once.
To remove the last item, use .pop(). It does two things: removes the last element AND returns it, so you can store it if you need it.
For the front of the array: .unshift() adds to the beginning (everything shifts right), and .shift() removes the first item. These are slower on large arrays because every other element has to be re-indexed, but for small arrays you will never notice.
Finally, .splice() is your power tool — it can remove items from any position, insert items anywhere, or do both at once. It is worth knowing, but push and pop will cover 80% of your real-world needs.
const taskList = ['write tests', 'fix bug', 'deploy app']; console.log('Original:', taskList); // UPDATE — change an existing item by its index taskList[1] = 'fix critical bug'; // replace item at index 1 console.log('After update:', taskList); // PUSH — add a new item to the END of the array taskList.push('send release notes'); console.log('After push:', taskList); // POP — remove and RETURN the last item const completedTask = taskList.pop(); // removes 'send release notes' console.log('Removed task:', completedTask); console.log('After pop:', taskList); // UNSHIFT — add an item to the FRONT (everything shifts right) taskList.unshift('review PR'); console.log('After unshift:', taskList); // SHIFT — remove and return the FIRST item const firstTask = taskList.shift(); console.log('Removed from front:', firstTask); console.log('After shift:', taskList); // SPLICE — remove 1 item starting at index 1 // Arguments: (startIndex, deleteCount) taskList.splice(1, 1); // removes 'fix critical bug' console.log('After splice:', taskList); // SPLICE to INSERT — add without removing // Arguments: (startIndex, 0, itemToInsert) taskList.splice(1, 0, 'write changelog'); console.log('After splice insert:', taskList);
After update: [ 'write tests', 'fix critical bug', 'deploy app' ]
After push: [ 'write tests', 'fix critical bug', 'deploy app', 'send release notes' ]
Removed task: send release notes
After pop: [ 'write tests', 'fix critical bug', 'deploy app' ]
After unshift: [ 'review PR', 'write tests', 'fix critical bug', 'deploy app' ]
Removed from front: review PR
After shift: [ 'write tests', 'fix critical bug', 'deploy app' ]
After splice: [ 'write tests', 'deploy app' ]
After splice insert: [ 'write tests', 'write changelog', 'deploy app' ]
Looping Through Every Item in an Array
Storing data in an array is only half the job — you almost always need to do something with every item. Looping is how you walk through an array element by element.
The classic for loop gives you full control: you start at index 0, keep going while the index is less than the array length, and increment by 1 each time. It is verbose but reliable, and it is perfect when you need the index number alongside the value.
The for...of loop is cleaner and more readable when you only care about the values themselves — you never touch an index number. This is the one you will use most often for reading and processing items.
The .forEach() method is the array's own built-in loop. You pass it a function, and it calls that function once per element, handing you the current item, its index, and the full array. It is great for readability.
Think of for...of as your daily driver and the classic for loop as your four-wheel-drive for when terrain gets tricky (needing the index, breaking early, counting backwards).
One thing to know now and revisit later: .map(), .filter(), and .reduce() are higher-order array methods that transform arrays rather than just reading them — they are the next level after loops and absolutely worth learning once this clicks.
const temperatures = [22, 17, 30, 25, 19, 28]; // METHOD 1: Classic for loop — use when you need the index console.log('--- Classic for loop ---'); for (let index = 0; index < temperatures.length; index++) { // index goes 0, 1, 2 ... up to (length - 1) console.log(`Day ${index + 1}: ${temperatures[index]}°C`); } // METHOD 2: for...of — cleanest syntax when you just need the value console.log('\n--- for...of loop ---'); for (const temp of temperatures) { // 'temp' holds the actual value, not the index if (temp >= 25) { console.log(`${temp}°C — hot day!`); } else { console.log(`${temp}°C — mild day.`); } } // METHOD 3: forEach — array's own built-in loop console.log('\n--- forEach ---'); temperatures.forEach((temp, index) => { // forEach hands you: (currentValue, currentIndex, theWholeArray) console.log(`Index ${index} → ${temp}°C`); }); // PRACTICAL EXAMPLE: Calculate the average temperature let total = 0; for (const temp of temperatures) { total += temp; // add each temperature to the running total } const average = total / temperatures.length; console.log(`\nAverage temperature: ${average.toFixed(1)}°C`);
Day 1: 22°C
Day 2: 17°C
Day 3: 30°C
Day 4: 25°C
Day 5: 19°C
Day 6: 28°C
--- for...of loop ---
22°C — mild day.
17°C — mild day.
30°C — hot day!
25°C — hot day!
19°C — mild day.
28°C — hot day!
--- forEach ---
Index 0 → 22°C
Index 1 → 17°C
Index 2 → 30°C
Index 3 → 25°C
Index 4 → 19°C
Index 5 → 28°C
Average temperature: 23.5°C
Searching and Transforming Arrays with Built-In Methods
JavaScript ships with a rich set of array methods that handle the most common tasks you will face — finding an item, checking if something exists, building a new array from an old one, or filtering down to only the items you care about. These methods save you from writing repetitive loop code.
.includes() answers the yes/no question: 'does this array contain this value?' It returns true or false.
.indexOf() goes further: it tells you the exact index where a value lives, or -1 if it is not found. The -1 return value is a JavaScript convention you will see everywhere.
.find() lets you search by a condition rather than an exact value. You give it a function that returns true when it finds a match, and it hands you back the actual element.
.map() creates a brand new array by transforming every element. The original array is never touched. Think of it as a factory conveyor belt — every item goes in, gets processed, and a new version comes out.
.filter() creates a new array containing only the items that pass a test. Think of it as a sieve — only items where your condition returns true make it through.
These five methods alone — includes, indexOf, find, map, and filter — will handle the vast majority of array work you do in real JavaScript projects.
const productPrices = [ { name: 'keyboard', price: 79 }, { name: 'mouse', price: 35 }, { name: 'monitor', price: 299 }, { name: 'webcam', price: 89 }, { name: 'headset', price: 149 }, ]; const productNames = ['keyboard', 'mouse', 'monitor', 'webcam', 'headset']; // INCLUDES — does this array contain 'monitor'? console.log(productNames.includes('monitor')); // true console.log(productNames.includes('tablet')); // false // INDEXOF — at what position is 'webcam'? const webcamPosition = productNames.indexOf('webcam'); console.log(`webcam is at index: ${webcamPosition}`); // 3 console.log(productNames.indexOf('tablet')); // -1 means NOT FOUND // FIND — give me the first product object where price > 100 const firstExpensiveProduct = productPrices.find( (product) => product.price > 100 // this runs once per item until true ); console.log('First expensive product:', firstExpensiveProduct); // MAP — create a NEW array of just the names (original untouched) const namesOnly = productPrices.map((product) => product.name); console.log('Names only:', namesOnly); // MAP — apply a 10% discount to every price, return new array const discountedPrices = productPrices.map((product) => ({ name: product.name, price: +(product.price * 0.9).toFixed(2), // + converts string back to number })); console.log('Discounted prices:', discountedPrices); // FILTER — only keep products under £100 const affordableProducts = productPrices.filter( (product) => product.price < 100 ); console.log('Affordable products:', affordableProducts);
false
webcam is at index: 3
-1
First expensive product: { name: 'monitor', price: 299 }
Names only: [ 'keyboard', 'mouse', 'monitor', 'webcam', 'headset' ]
Discounted prices: [
{ name: 'keyboard', price: 71.1 },
{ name: 'mouse', price: 31.5 },
{ name: 'monitor', price: 269.1 },
{ name: 'webcam', price: 80.1 },
{ name: 'headset', price: 134.1 }
]
Affordable products: [
{ name: 'keyboard', price: 79 },
{ name: 'mouse', price: 35 },
{ name: 'webcam', price: 89 }
]
| Method | What It Returns | Modifies Original? | Best Used For |
|---|---|---|---|
| .push(item) | New array length | Yes | Adding an item to the end |
| .pop() | The removed item | Yes | Removing the last item |
| .map(fn) | New transformed array | No | Transforming every element |
| .filter(fn) | New filtered array | No | Keeping only matching items |
| .find(fn) | First matching element or undefined | No | Getting one item by condition |
| .includes(val) | true or false | No | Checking if a value exists |
| .indexOf(val) | Index number or -1 | No | Finding a value's position |
| .splice(i, n) | Array of removed items | Yes | Removing/inserting at any index |
🎯 Key Takeaways
- JavaScript arrays are zero-indexed — the first item is always at index 0, and the last item is always at index
array.length - 1, never atarray.length. .push()and.pop()modify the original array;.map()and.filter()always return a brand-new array and never touch the original — this distinction matters enormously in real projects.- Use
for...ofwhen you only need values, a classicforloop when you need the index number or want to break out early, and.forEach()when passing a named callback function. - Getting
undefinedwhen reading an array element means you asked for an index that does not exist — it is not a crash, but it is a signal your index logic is off by one or your array is shorter than you expected.
⚠ Common Mistakes to Avoid
- ✕Mistake 1: Using index 1 to access the first element instead of index 0 — Symptom: you get the second item instead of the first, or
undefinedwhen accessingarray[array.length]— Fix: always remember arrays start at 0; the first item isarray[0]and the last isarray[array.length - 1]. - ✕Mistake 2: Expecting
.push()to return the new array instead of the new length — Symptom: you writeconst updated = myArray.push('newItem')and then wonder whyupdatedis a number like4, not an array — Fix:.push()mutates the original array in place and returns the new length; just callmyArray.push('newItem')and continue usingmyArraydirectly. - ✕Mistake 3: Using
constand assuming the array can never change — Symptom: you declareconst colors = ['red', 'blue'], then try.push('green')and are surprised it works, or you incorrectly thinkconstmeans the array is locked — Fix:constonly prevents you from reassigning the variable to a completely different value; the array's contents can still be modified freely. To truly freeze an array, useObject.freeze(colors).
Interview Questions on This Topic
- QWhat is the difference between `.map()` and `.forEach()` in JavaScript, and when would you choose one over the other?
- QIf I have an array of 100 user objects and I want to get a new array containing only users who are over 18 and have verified their email, how would you approach that in one readable line?
- QWhat does `.splice()` return, and how is it different from `.slice()`? — This one catches people out because the names sound almost identical but they behave completely differently.
Frequently Asked Questions
Can a JavaScript array hold different types of values like numbers and strings together?
Yes — JavaScript arrays can hold any mix of types including numbers, strings, booleans, objects, and even other arrays. That said, mixing types in a single array is usually a sign of a design problem. In practice, keep one array focused on one kind of data to make your code predictable and easy to debug.
What is the difference between JavaScript array `.slice()` and `.splice()`?
.slice(start, end) returns a new array copied from the original between two indexes — it never modifies the original. .splice(start, deleteCount) modifies the original array by removing or inserting items in place and returns the removed items. If you want a safe copy of a portion, use .slice(). If you want to actually change the array, use .splice().
Why do I get `undefined` when I try to read an array element?
You are accessing an index that does not exist in the array. The most common causes are: reading index array.length instead of array.length - 1 (off-by-one error), or the array is empty. JavaScript does not throw an error for out-of-bounds access — it silently returns undefined. Always double-check your index logic and verify the array has items before accessing them.
Written and reviewed by senior developers with real-world experience across enterprise, startup and open-source projects. Every article on TheCodeForge is written to be clear, accurate and genuinely useful — not just SEO filler.