Suggest an editImprove this articleRefine the answer for “Array methods vs loops”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Array methods are abstractions over loops, and they pay for that convenience with overhead: a callback call on every iteration, three arguments `(element, index, array)` passed in, internal checks, and, for `map` or `filter`, a freshly allocated result array.** A plain `for` does none of that: the engine inlines the loop body and the JIT optimises it more easily because the code is predictable and has no wrappers. On small data the difference is a fraction of a millisecond and can be ignored, but on millions of elements or in hot code (rendering, parsing, canvas, aggregations) `for` can be 2 to 5 times faster. The extra allocations also load the garbage collector. ```javascript // Slower: callback call per item plus a freshly allocated array const doubled1 = arr.map(x => x * 2); // Faster: no callback, result array preallocated const doubled2 = new Array(arr.length); for (let i = 0; i < arr.length; i++) doubled2[i] = arr[i] * 2; ``` **Key point:** array methods are slower because of callbacks, allocations and internal checks, but reach for `for` only where a profiler showed a bottleneck.Shown above the full answer for quick recall.Answer (EN)Image**Array methods (`map`, `filter`, `forEach`, `reduce` and friends) are abstractions over loops, implemented inside the JavaScript engine.** They are more convenient, shorter and more readable, but they carry extra overhead, which can make them slower than plain `for`, `for...of` and `while` loops, especially on large arrays. ## Theory ### TL;DR - An array method calls a callback on every iteration and passes it three arguments, while `for` simply runs the loop body. - `map`, `filter`, `slice`, `concat` also allocate a new array, which means new memory and more work for the GC. - A bare `for` is predictable, so the JIT compiler (V8, SpiderMonkey) optimises it more easily. - On a million elements `for` can be 2 to 5 times faster; on ten thousand the difference is a fraction of a millisecond. - In ordinary product code readability beats that difference, so `.map()` in JSX is perfectly fine. - Optimise only hot paths: rendering, parsing, binary data processing, canvas, heavy aggregations. ### Quick example ```javascript const arr = Array.from({ length: 1_000_000 }, (_, i) => i); // map console.time('map'); const doubled1 = arr.map(x => x * 2); console.timeEnd('map'); // for console.time('for'); const doubled2 = new Array(arr.length); for (let i = 0; i < arr.length; i++) { doubled2[i] = arr[i] * 2; } console.timeEnd('for'); ``` On most engines the result looks roughly like this: ```text map: 30-60 ms for: 10-20 ms ``` ### What happens under the hood When you write: ```javascript arr.map(x => x * 2); ``` the engine does roughly the following: 1. Checks that `arr` really is an array. 2. Creates a new array for the results. 3. On every iteration: - calls the callback function; - passes it three arguments `(element, index, array)`; - stores the result in the new array. 4. Returns the resulting array. That is a pile of steps which add overhead compared to a plain `for` loop, where you just run the instructions with no wrappers and no checks. ### Why exactly it is slower | Reason | What happens | | --- | --- | | **Callback function** | A function is called on every iteration, so there are extra call stack frames | | **Allocating a new array** | `map`, `filter`, `slice`, `concat` create copies, which costs extra memory | | **Checks and context** | The method runs validations: length, holes, prototype, type | | **Unoptimised closures** | If the callback captures outer variables, the overhead grows further | | **Functional principles** | These methods are pure and do not mutate the data, so more allocations are needed | | **Loops are easier for the JIT to optimise** | The engine (V8, SpiderMonkey) optimises a bare `for` faster | ### Why it shows up in hot paths > If a loop runs millions of times (rendering, sorting, data aggregation, parsing), callback overhead starts to cost real money. In those places: - every callback call is a new call stack frame; - extra allocations mean more work for the GC (garbage collector); - the extra arguments (`index`, `array`) mean more objects in memory. ### When it does not matter For most business tasks (lists, filters, mapping up to ten thousand elements): - the difference between `for` and `map` is a fraction of a millisecond; - readability and clean code matter more. That is exactly why React/Vue code uses `.map()` for JSX: it is declarative and clear. ```javascript {items.map(item => <Card key={item.id} {...item} />)} ``` But if you have an array of millions of elements, or a loop in a hot spot (rendering, binary data processing, canvas, a parser), prefer: ```javascript for (let i = 0; i < n; i++) { /* ... */ } ``` ### What is actually faster, in order | Loop | Speed | Notes | | --- | --- | --- | | `for (let i = 0; i < n; i++)` | Fastest | No checks, inlined, predictable | | `for...of` | Fast, but uses an iterator | Some overhead | | `while` | Roughly the same as `for` | Depends on the engine | | `forEach()` | Slower (callback) | Does not return a new array | | `map()` | Slower | Allocates a new array | | `filter()`, `reduce()` | Slower still | Allocations, extra operations | ### How to speed up array methods | Method | Optimisation | | --- | --- | | `.map()` | Use a pure arrow function with no outer closures | | `.filter()` | Do not chain `.map().filter().reduce()`, merge them into a single pass | | `.reduce()` | For complex operations move the accumulation into a `for` | | `.forEach()` | Replace with `for` or `for...of` in hot code | | `.concat()` / spread (`[...a, ...b]`) | On large arrays replace with `push.apply()` or a loop | A short summary of the reasons: | Reason | Why it is slower | | --- | --- | | Callback functions | Create extra calls and context | | A new array | New memory is allocated | | Validations and iteration | Built in checks and protocols | | GC pressure | Temporary objects are created | | Loops are simpler | Easier for the JIT compiler to optimise | Conclusion: for performance critical tasks use `for`, for clear declarative code use `map`, `filter`, `reduce`. ### Common mistakes - **Rewriting all code as `for` loops "for speed".** Without measuring this loses readability with no gain: in 99% of places the difference is invisible. - **Chaining `.map().filter().reduce()` on large arrays.** Every link walks the whole array and allocates an intermediate one. A single loop or a single `reduce` does the same job in one pass. - **Confusing `forEach` and `for` when you need to exit early.** You cannot `break` out of `forEach` or `return` from the outer function; working around it with `throw` costs more than a plain loop. - **Assuming `for...of` is as fast as a classic `for`.** It goes through the iterator protocol and creates a `{ value, done }` object on every step. - **Forgetting to preallocate the array.** `new Array(n)` with index assignment is cheaper than `push()` in a loop over millions of elements. - **Micro optimising instead of changing the algorithm.** Turning O(n squared) into O(n) buys far more than any `map` to `for` swap.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.