Mid-level 5 min · March 05, 2026

JavaScript push() Returns Length — The Silent Sort Bug

push() returns array length, not the array.

N
Naren · Founder
Plain-English first. Then code. Then the interview question.
About
 ● Production Incident 🔎 Debug Guide
Quick Answer
  • 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
Plain-English First

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.

io/thecodeforge/js/creatingAndReadingArrays.jsJAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 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
Watch Out: Zero-Indexing Bites Everyone Once
If your array has 5 items, the valid indexes are 0, 1, 2, 3, and 4. Index 5 does not exist — you get undefined. Always use array[array.length - 1] to safely grab the last item regardless of array size.
Production Insight
Accessing an out-of-bounds index returns undefined, not an exception. This silent failure can cause bugs that propagate far from the original access.
Always validate array length before access: if (index >= 0 && index < arr.length) { / safe / }.
Rule: for production code, assume user input can be an index and validate it. arr[userInput] can read undefined or crash if userInput is non-numeric (returns undefined, but no error).
Key Takeaway
JavaScript arrays are zero-indexed — first item at index 0, last at array.length - 1.
Out-of-bounds access returns undefined silently — no exception like Java.
Rule: Use 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.

io/thecodeforge/js/modifyingArrays.jsJAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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);
Pro Tip: push/pop vs shift/unshift Performance
.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.
Production Insight
push returns the new length (number), not the array. This is the single most common array API mistake in production JavaScript.
pop returns the removed element (any type), shift returns the removed first element. unshift returns the new length.
Rule: Every mutating array method returns something different. Know the return value before using it in a chain. Check MDN or test in console.
Key Takeaway
push/pop work at the end — O(1). shift/unshift work at the front — O(n). Use push/pop by default for better performance.
push/unshift return new length; pop/shift return the removed element. Don't assume push returns the array.
Rule: Use splice for middle modifications; it's O(n) but necessary.

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.

io/thecodeforge/js/loopingThroughArrays.jsJAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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`);
Interview Gold: Which Loop Should You Use?
Use 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.
Production Insight
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.
Rule: Never use 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.
Key Takeaway
Use for...of when you only need values, classic for when you need the index or break early, forEach for callbacks.
Never use for...in with arrays — it iterates over enumerable properties, not just numeric indexes.
Rule: for...of is the safe default for reading all elements. Classic for loop is needed for modifying while iterating.

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.

io/thecodeforge/js/arrayMethods.jsJAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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);
Pro Tip: map and filter Never Modify the Original
.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.
Production Insight
map, filter, reduce, and find do not modify the original array. They return new values.
push, pop, shift, unshift, splice modify the original array in place. This distinction is critical in React state updates.
Rule: For transforming data (map, filter), assign the result to a new variable or state setter. For side effects (logging, DOM updates), use forEach.
Key Takeaway
map creates a new array by transforming every element; filter creates a new array with only matching elements.
Neither modifies the original array — they are immutable by design.
Rule: Use map/filter for transformations, forEach for side effects. map returns an array; forEach returns undefined.
● Production incidentPOST-MORTEMseverity: high

The push() Length Bug That Broke the Leaderboard

Symptom
The leaderboard showed scores in random order. The team added new scores, and the ordering was inconsistent. No errors in console. The array had the correct values, but sorting never happened. The leaderboard relied on scores.sort() but the variable holding 'sorted' was actually the length.
Assumption
The developer assumed .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.
Root cause
JavaScript's 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.
Fix
1. Separated the push and sort operations: 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).
Key lesson
  • 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);
Production debug guideSymptom → Action mapping for common array failures in production JavaScript applications.5 entries
Symptom · 01
Array seems to have extra properties or iterates over unexpected keys
Fix
You used 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.
Symptom · 02
Array modification inside loop causes unexpected behaviour
Fix
You're modifying the array while iterating with forEach or for...of. Use a standard for loop counting backward: for (let i = arr.length - 1; i >= 0; i--) when removing items, or create a copy: [...arr].forEach(item => {...})
Symptom · 03
push() result used as array — TypeError: .sort not a function
Fix
push returns length (number), not array. Separate operations: arr.push(value); process(arr);. Check return value type with typeof during debugging.
Symptom · 04
Array length is correct but some elements are undefined
Fix
You created a sparse array (e.g., arr[1000] = 'value' without filling indices 0-999). Use Array(length).fill(default) or [...Array(length)] to create dense arrays.
Symptom · 05
map/filter not updating UI in React
Fix
map returns a new array; you must assign it to state: setItems(items.map(i => i 2)). Direct mutation items.map(i => i 2) does nothing because the return value is unused.
★ JavaScript Array Debug Cheat SheetFast diagnostics for array issues in production JS. Run these in the browser console first.
Array iteration gives unexpected keys or values
Immediate action
Check if using for...in instead of for...of
Commands
console.log(Object.keys(myArray)); // see all enumerable keys
for (let val of myArray) { console.log(val); } // correct
Fix now
Replace for (let key in arr) with for (let val of arr) or arr.forEach(val => ...)
push result used as array — sort/filter throws error+
Immediate action
Check type of variable after push
Commands
let result = arr.push(5); console.log(typeof result); // 'number'
console.log('Is array?', Array.isArray(result)); // false
Fix now
Separate operations: arr.push(value); const sorted = [...arr].sort();
Array has length but elements are undefined+
Immediate action
Check if array is sparse (holes) or has explicit undefined values
Commands
console.log(Object.hasOwn(arr, 0)); // false if hole
console.log(arr.every(el => el === undefined)); // true if all undefined
Fix now
Create dense array: Array(length).fill(initialValue) or [...Array(length)] then map.
sort not working as expected+
Immediate action
Check if sorting numbers without compare function
Commands
console.log([1, 10, 2].sort()); // [1, 10, 2] — alphabetical!
console.log([1, 10, 2].sort((a,b) => a - b)); // [1, 2, 10]
Fix now
Add compare function: arr.sort((a,b) => a - b) for numbers, arr.sort((a,b) => a.localeCompare(b)) for strings.
map returning new array but original unchanged (expected)+
Immediate action
Check if you assigned the result
Commands
let doubled = arr.map(x => x * 2); console.log(arr, doubled);
arr = arr.map(x => x * 2); // assign back to variable
Fix now
map does not modify original; assign result to new variable or back to same one.
JavaScript Array Methods — Mutating vs Non-Mutating
MethodWhat It ReturnsModifies Original?Time ComplexityBest Used For
.push(item)New array length (number)YesO(1)Adding an item to the end
.pop()The removed item (any type)YesO(1)Removing last item, storing it
.shift()The removed first itemYesO(n)Removing first item (queue operation)
.unshift(item)New array length (number)YesO(n)Adding item to front
.splice(start, deleteCount, ...items)Array of removed itemsYesO(n)Removing/inserting at any index
.map(fn)New transformed array (same length)NoO(n)Transforming every element
.filter(fn)New filtered array (0 to original length)NoO(n)Keeping only matching items
.find(fn)First matching element or undefinedNoO(n) worst caseGetting one item by condition
.includes(val)true or falseNoO(n)Checking if a value exists (exact)
.indexOf(val)Index number or -1NoO(n)Finding a value's position
.reduce(fn, init)Accumulated single value (any type)NoO(n)Summing, grouping, complex accumulation
.forEach(fn)undefinedNo (but callback can mutate if not careful)O(n)Side effects (logging, DOM updates)

Key takeaways

1
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 at array.length.
2
.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.
3
Use for...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.
4
Getting undefined when 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.
5
Never use for...in for arrays
it iterates over enumerable properties including prototype methods. Use for...of, classic for, or forEach.

Common mistakes to avoid

5 patterns
×

Using index 1 to access the first element instead of index 0

Symptom
You get the second item instead of the first, or undefined when accessing array[array.length] because you thought the last index was length not length-1.
Fix
Always remember arrays start at 0; the first item is 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

Symptom
You write 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.
Fix
.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

Symptom
The loop runs, but the variable is the index (as a string), not the value. If you extended Array.prototype, those method names also appear as keys. The loop order is not guaranteed to be insertion order.
Fix
Use 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

Symptom
[1, 10, 2].sort() returns [1, 10, 2] not [1, 2, 10]. Sort converts elements to strings and sorts lexicographically (dictionary order).
Fix
Always provide a compare function for numeric arrays: 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

Symptom
Items are skipped or processed twice. Removing the current element shifts the remaining indices, and the loop skips the next item because the index increments past it.
Fix
Iterate backward with a classic for loop: 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 PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
What is the difference between `.map()` and `.forEach()` in JavaScript, ...
Q02JUNIOR
How would you get a new array containing only users who are over 18 and ...
Q03JUNIOR
What does `.splice()` return, and how is it different from `.slice()`? —...
Q04SENIOR
How would you remove duplicate values from an array efficiently?
Q01 of 04JUNIOR

What is the difference between `.map()` and `.forEach()` in JavaScript, and when would you choose one over the other?

ANSWER
.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.
FAQ · 4 QUESTIONS

Frequently Asked Questions

01
Can a JavaScript array hold different types of values like numbers and strings together?
02
What is the difference between JavaScript array `.slice()` and `.splice()`?
03
Why do I get `undefined` when I try to read an array element?
04
How do I check if a variable is an array in JavaScript?
🔥

That's JS Basics. Mark it forged?

5 min read · try the examples if you haven't

Previous
Functions in JavaScript
6 / 16 · JS Basics
Next
Objects in JavaScript