JavaScript push() Returns Length — The Silent Sort Bug
push() returns array length, not the array.
- Array = ordered list of values, accessed by zero-based index: arr[0] first, arr[arr.length-1] last
- Key methods: push/pop (end), shift/unshift (front), splice (anywhere), for...of (iteration), map/filter (transform)
- Performance: push/pop O(1), shift/unshift O(n) because all other elements re-index, splice O(n)
- Production trap: Using for...in instead of for...of — iterates over array properties, not just numeric indexes
- Biggest mistake: Expecting .push() to return the new array — it returns the new length, causing silent bugs
Think of an array like a numbered egg carton. Each slot holds one egg (a value), and every slot has a number printed on it starting from zero — so the first egg is in slot 0, the second in slot 1, and so on. Instead of reaching into a random carton and guessing where the eggs are, you can say 'give me the egg in slot 2' and get exactly what you asked for. That is all an array is: an ordered list of things, where every item has a numbered address.
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 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.
undefined. Always use array[array.length - 1] to safely grab the last item regardless of array size.undefined, not an exception. This silent failure can cause bugs that propagate far from the original access.if (index >= 0 && index < arr.length) { / safe / }.arr[userInput] can read undefined or crash if userInput is non-numeric (returns undefined, but no error).array.length - 1.undefined silently — no exception like Java.array[array.length - 1] for last element, not array[array.length].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.
.push() and .pop() only touch the end of the array — O(1) speed. .shift() and .unshift() re-index every element — O(n) speed. For large arrays (thousands of items), prefer working with the end of the array whenever you can.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.
for...of when you only need values. Use a classic for loop when you need the index or want to break early with break. Use .forEach() when passing a reusable callback function. Never use for...in for arrays — it iterates over properties, not values.for...in iterates over array indexes as strings AND any enumerable properties added to the array or its prototype. This includes methods if someone extends Array.prototype.for...of iterates only over array element values, in insertion order, and is safe for arrays.for...in for arrays in production. Use for...of for values, classic for for index access, or forEach for readability when you don't need to break early.for...of when you only need values, classic for when you need the index or break early, forEach for callbacks.for...in with arrays — it iterates over enumerable properties, not just numeric indexes.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.
.map() and .filter() always return brand-new arrays — the original array stays unchanged. This is called immutability, and it prevents a whole category of bugs. If your original data changed unexpectedly after using these methods, you are probably using .forEach() and mutating manually instead.The push() Length Bug That Broke the Leaderboard
scores.sort() but the variable holding 'sorted' was actually the length..push() returned the new array because it 'adds an item'. They learned from other languages (Java ArrayList returns boolean). They didn't read the MDN documentation or test the return value. The code worked in development because with 3 items, scores.push(10) returned 4, and 4.sort() did nothing? Actually, 4.sort() throws TypeError: 4.sort is not a function. But the error was caught by a generic try-catch that displayed a default unsorted list, masking the bug.Array.prototype.push() returns the new length of the array, not the array itself. The team wrote const sortedScores = scores.push(newScore).sort();. scores.push(newScore) returned a number (the new length), and the code attempted .sort() on that number, throwing a TypeError. The error handler caught it and fell back to displaying the array without sorting. The bug was invisible in the UI except for the missing sort order. The team spent 2 days chasing a sorting algorithm bug before noticing the error handler's log.scores.push(newScore); const sortedScores = [...scores].sort((a,b) => b - a);
2. Added a lint rule: no-array-push-return to catch assuming push returns array.
3. Replaced the generic try-catch with specific error handling that logs stack traces.
4. Added unit test that verifies the leaderboard displays sorted scores after adding new ones.
5. Documented that push/pop/shift/unshift modify in-place and return different values (length or removed element).Array.push()returns the NEW LENGTH, not the array. Column: push/pop/unshift/shift modify the original array in place.- map/filter/reduce return new arrays; push/pop return numbers or removed elements. Know which category your method belongs to.
- Generic try-catch blocks hide bugs. Only catch exceptions you can handle; let others crash loudly in development.
- MDN is your friend. The return value is documented. When in doubt, test in console:
let a = [1]; let b = a.push(2); console.log(b);
for...in instead of for...of. for...in iterates over all enumerable properties, including array prototype methods and added custom keys. Replace with for...of (values) or forEach.for (let i = arr.length - 1; i >= 0; i--) when removing items, or create a copy: [...arr].forEach(item => {...})arr.push(value); process(arr);. Check return value type with typeof during debugging.arr[1000] = 'value' without filling indices 0-999). Use Array(length).fill(default) or [...Array(length)] to create dense arrays.setItems(items.map(i => i 2)). Direct mutation items.map(i => i 2) does nothing because the return value is unused.for (let key in arr) with for (let val of arr) or arr.forEach(val => ...)Key takeaways
array.length - 1, never at array.length..push() and .pop() modify the original array; .map() and .filter() always return a brand-new array and never touch the originalfor...of when you only need values, a classic for loop when you need the index number or want to break out early, and .forEach() when passing a named callback function.undefined when reading an array element means you asked for an index that does not existfor...in for arraysfor...of, classic for, or forEach.Common mistakes to avoid
5 patternsUsing index 1 to access the first element instead of index 0
undefined when accessing array[array.length] because you thought the last index was length not length-1.array[0] and the last is array[array.length - 1]. Never hardcode array.length as an index.Expecting .push() to return the new array instead of the new length
const updated = myArray.push('newItem') and then wonder why updated is a number like 4, not an array. Chaining .sort() or .map() on the result throws an error..push() mutates the original array in place and returns the new length. Just call myArray.push('newItem') and continue using myArray directly. For chaining, add item first then chain on the array reference.Using `for...in` to iterate over array values
for...of for values: for (const val of arr). Use classic for for index access: for (let i = 0; i < arr.length; i++). Use forEach for callbacks. Never use for...in with arrays.Assuming .sort() works without a compare function for numbers
[1, 10, 2].sort() returns [1, 10, 2] not [1, 2, 10]. Sort converts elements to strings and sorts lexicographically (dictionary order).arr.sort((a, b) => a - b) for ascending, (a, b) => b - a for descending. For strings, arr.sort((a, b) => a.localeCompare(b)) for proper alphabetical sorting.Modifying an array while iterating with forEach or for...of
for (let i = arr.length - 1; i >= 0; i--) { if (condition) arr.splice(i, 1); }. Or use filter to create a new array without mutating during iteration. For read-modify, use map.Interview Questions on This Topic
What is the difference between `.map()` and `.forEach()` in JavaScript, and when would you choose one over the other?
.map() creates and returns a new array containing the results of applying a callback to every element. It's for transformation: input array length equals output array length. .forEach() executes a callback on every element but returns undefined. It's for side effects: logging, DOM updates, mutating external state. Choose map when you need a transformed array; choose forEach when you just need to do something with each element and don't need a return array. Using forEach to create an array by pushing into an external accumulator is an anti-pattern — use map instead. Also, map can be chained with filter, reduce, etc., because it returns an array; forEach returns undefined so cannot be chained.Frequently Asked Questions
That's JS Basics. Mark it forged?
5 min read · try the examples if you haven't