Why for…in Breaks JavaScript Arrays and How for…of Fixes It
This article examines a production incident caused by using the ES5 for...in loop to iterate over arrays, explains its pitfalls such as prototype pollution and string indexes, and demonstrates why switching to the ES6 for...of construct provides safer, more predictable array traversal.
In this article we analyze a production incident caused by using the ES5 for...in loop to iterate over arrays, and recommend switching to the ES6 for...of construct.
Problem Identification
1. Problem Description
The purchase order feature, running for over six months, suddenly stopped working.
Inspection of the static code revealed that array traversal used for...in , which is discouraged for arrays; for...of is recommended.
Problem code: <code>calculateAllValues(){ let sellPlan = this.query.sellPlan let vm = this let totalSellProfit = 0 let sellProfitCount = 0 vm.totalSellFee = 0 vm.totalSellRate = 0 vm.averageSellProfit = 0 for (let index in sellPlan) { sellPlan[index].sellRate = vm.formateNumber(sellPlan[index].sellRate, 2) vm.totalSellRate += Number(sellPlan[index].sellRate) // ... } // ... }</code>
Changing the loop to for...of resolves the issue.
But why does for...in have defects?
2. Problem Analysis
Check recent creation times of purchase orders.
Find a newly deployed contract project.
Inspect its JavaScript source; the contract project extended the native Array prototype, causing for...in to enumerate added properties.
Contract project code that adds a method to Array: <code>Array.prototype.sm_remove = function(dx) { if (isNaN(dx) || dx > this.length) { return false } this.splice(dx, 1) }</code>
The for...in loop is an ES5 feature that iterates over all enumerable properties, including those added to the prototype, which can lead to errors when traversing arrays.
Example:
<code>Array.prototype.fatherName = "Father";
const arr = [1, 2, 3];
arr.name = "Hello world";
for (let index in arr) {
console.log("arr[" + index + "] = " + arr[index]);
}</code>Result:
<code>arr[0] = 1
arr[1] = 2
arr[2] = 3
arr[name] = Hello world
arr[fatherName] = Father</code>3. Defects of for...in
Indexes are strings, preventing direct arithmetic.
Iteration order may not match the array’s internal order.
All enumerable properties, including prototype extensions, are visited.
Thus for...in is better suited for objects, not arrays.
For simple and correct array traversal, ES6 for...of is superior.
4. What for...of Can Do
Unlike Array.prototype.forEach , it respects break , continue , and return statements.
It works with arrays and most array‑like objects such as DOM NodeLists.
It can iterate over strings, treating them as sequences of Unicode characters.
It also supports iteration of Map and Set objects introduced in ES6.
Conclusion
Avoid using ES5 for...in for array traversal; prefer ES6 for...of . Use for...in for objects.
Generally, do not extend built‑in constructors’ prototypes.
If you must use for...in on arrays, guard against prototype properties with Object.hasOwnProperty .
Note that for...of does not work on plain objects; use for...in for that purpose.
Vipshop Quality Engineering
Technology exchange and sharing for quality engineering
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.