|
1 |
| -### Arrays |
| 1 | +## Arrays |
2 | 2 |
|
3 |
| -Although the `Array` in JavaScript is an `Object`, there's no good reason to use |
4 |
| -the [for in loop](#forinloop) in order to iterate over it. In fact there |
5 |
| -a number of very good reasons **against** the use of `for in` on an `Array`. |
| 3 | +Although arrays in JavaScript are objects, there are no good reasons to use |
| 4 | +the [for in loop](#forinloop) in for iteration on them. In fact there are a |
| 5 | +number of good reasons **against** the use of `for in` on arrays. |
6 | 6 |
|
7 |
| -> **Note:** There are **no** so called *associative arrays* in JavaScript. |
8 |
| -> JavaScript only has [objects](#objects) for mapping keys to values. And while |
9 |
| -> *associative arrays* **preverse** order, objects do **not**. |
| 7 | +> **Note:** JavaScript arrays are **not** *associative arrays*. JavaScript only |
| 8 | +> has [objects](#objects) for mapping keys to values. And while associative |
| 9 | +> arrays **preserve** order, objects do **not**. |
10 | 10 |
|
11 |
| -While it may seem like a good choice at first, to trade the some speed against |
12 |
| -the readability of the `for in` construct, this has **major** implications on |
13 |
| -performance. |
| 11 | +Since the `for in` loop enumerates all properties on the prototype chain and |
| 12 | +the only way to exclude those properties is to use |
| 13 | +[`hasOwnProperty`](#hasownproperty), it is already up to **twenty times** slower |
| 14 | +than a normal `for` loop. |
14 | 15 |
|
15 |
| -The `for in` does in fact iterate over the indexes of an `Array`. But it does |
16 |
| -also traverse the prototype chain. So one already has to use `hasOwnProperty` in |
17 |
| -order to make sure to filter out unwanted properties, and still if any |
18 |
| -additional properties happen to be defined on the array, they will still make it |
19 |
| -through this filter. |
| 16 | +### Iteration |
20 | 17 |
|
21 |
| -Combining the already slow nature of the prototype traversing `for in` with the |
22 |
| -use of `hasOwnProperty` results in a performance degradation of a factor of up |
23 |
| -to **20x**. |
24 |
| - |
25 |
| -So if you want to iterate over an `Array` in JavaScript, **always** use the |
26 |
| -classic `for` loop construct. |
| 18 | +In order to achieve the best performance when iterating over arrays, it is best |
| 19 | +to use the classic `for` loop. |
27 | 20 |
|
28 | 21 | var list = [1, 2, 3, 4, 5, ...... 100000000];
|
29 | 22 | for(var i = 0, l = list.length; i < l; i++) {
|
30 | 23 | console.log(list[i]);
|
31 | 24 | }
|
32 | 25 |
|
33 |
| -As you can see, there's one extra catch in the above example. That is the |
34 |
| -caching of the length via `l = list.length`. |
| 26 | +There is one extra catch in the above example, which is the caching of the |
| 27 | +length of the array via `l = list.length`. |
| 28 | + |
| 29 | +Although the `length` property is defined on the array itself, there is still an |
| 30 | +overhead for doing the lookup on each iteration of the loop. And while recent |
| 31 | +JavaScript engines **may** apply optimization in this case, there is no way of |
| 32 | +telling whether the code will run on one of these newer engines or not. |
35 | 33 |
|
36 |
| -Although the `length` property is defined on the array itself, there's still an |
37 |
| -overhead for doing the lookup on each iteration. And while recent JavaScript |
38 |
| -engines **may** apply optimization in this case, one can never be sure that |
39 |
| -those optimizations are actually in place, nor can one be sure whether they |
40 |
| -reach the speed of the above caching. In fact leaving out the caching may result |
41 |
| -in a performance degradation of a factor of up to **2x** (and even more in older |
42 |
| -engines). |
| 34 | +In fact, leaving out the caching may result in the loop being only **half as |
| 35 | +fast** as with the cached length. |
43 | 36 |
|
44 |
| -**The length Property** |
| 37 | +### The `length` property |
45 | 38 |
|
46 |
| -The `length` property of an `Array` is not just a plain property. While its |
47 |
| -`getter` just returns the number of elements in the array, its `setter` on |
48 |
| -the other hand can be used to **truncate** the array. |
| 39 | +While the *getter* of the `length` property simply returns the number of |
| 40 | +elements that are contained in the array, the *setter* can be used to |
| 41 | +**truncate** the array. |
49 | 42 |
|
50 | 43 | var foo = [1, 2, 3, 4, 5, 6];
|
51 | 44 | foo.length = 3;
|
52 | 45 | foo; // [1, 2, 3]
|
| 46 | + |
53 | 47 | foo.length = 6;
|
54 | 48 | foo; // [1, 2, 3]
|
55 | 49 |
|
56 |
| -As one can see, assigning a smaller length truncates the array, but increasing |
57 |
| -the length it has no effect at all. |
| 50 | +Assigning a smaller length does truncate the array, but increasing the length |
| 51 | +does not have any effect on the array. |
| 52 | + |
| 53 | +### In conclusion |
| 54 | + |
| 55 | +For the best performance it is recommended to always use the plain `for` loop |
| 56 | +and cache the `length` property. The use of `for in` on an array is a sign of |
| 57 | +badly written code that is prone to bugs and bad performance. Additionally, |
| 58 | +never should any assumptions be made whether the JavaScript engine will apply |
| 59 | +optimization to the code or not. |
58 | 60 |
|
59 |
| -#### Best Practices |
60 |
| -Always use the `for` construct and cache the length to achieve the best |
61 |
| -performance, don't make any assumptions about the JavaScript engine optimizing |
62 |
| -**anything**. |
63 |
| - |
0 commit comments