Which is faster in JavaScript: looping through an array with integer indices or looping through an object with properties? What is the performance difference, if any?
var array = [1, 2, 3];
for (var i = 0; i < array.length; i++) {
}
Compared to:
var object = {"1":1, "2":2, "3":3};
for (var x in object) {
}
To the best of my understanding JavaScript arrays are actually backed by a map, so I would expect both to perform the same. Any information is greatly appreciated!
EDIT: I should probably clarify that I'm interested in the loop overhead (like if for in is more expensive) and also the lookup time of accessing each element (object[x] vs array[i]).
The accepted answer uses an invalid benchmark and is completely wrong. As the comments point out console.log will dominate the test results, rendering them useless. Take a look at this comparison: http://jsperf.com/performance-of-array-vs-object/17
Array iteration is about 48 times faster than object iteration. It improves considerably if you know the range of the keys of the object in advance, but is still significantly slower than array iteration.
i created a jsperf http://jsperf.com/array-vs-object-loop.
i thought the extra property-access would need more time. in chrome 24 it doesnt make much of a difference, in firefox 19 the object way needs 5-10% longer.
you should probably also take the size of the object/array into account.
EDIT: forget about that answer, an take a look at the accepted one!
Related
Curiosity only sponsors this question, as it's always fun to hack in languages.
Assume that there is an array holding objects of some kind. Objects have an id property. Id cannot be empty string, false, null or any falsey value. Array can be of zero length. I want to obtain index of this value (if present) and exit the loop as soon as it's found.
var id = /some value to check/;
var index;
for (var i = 0, item; item = arr[i],
item===undefined?false:item.id==id?(index=i,false):true; i++);
What do you think?
Meanwhile I did jsperf with posted above suggestions. Please play around if you want.
jsperf mentioned
Fastest are my initial example above under FF and my while loop posted in comments under Chrome. find solution with arrow functions is slowest in both cases. Cannot test in IE as I use no Win.
I'm aware this jsperf is badly written - please play around.
I commonly see developers use an expression like the following in JavaScript:
arr = []
arr[arr.length] = "Something"
arr[arr.length] = "Another thing"
Wouldn't push be more appropriate?
arr = []
arr.push("Something")
arr.push("Another thing")
I actually asked myself the same question at the start of this year. UPDATED with new test cases http://jsperf.com/array-push-vs-unshift-vs-direct-assignment/2
It appears that push is much faster in chrome, and about equal in FF. Also direct is faster in IE9, but I would be interested to see how it performs in IE10.
I would say that most developers would assume setting the length of the array, and then using direct assignment is faster, as is the case with most programming languages. But JavaScript is different. Javascript arrays aren't really arrays, they're just key/value maps just like all other JavaScript objects. So the pre-allocation is essentially falling on deaf ears.
Personally I prefer push (:
I believe that it's mostly habit.
Some developers use it simply because it's the way they are used to do it, and haven't considered that push would be an alternative.
Some developers have learned once upon a time that one method is much faster than another, and haven't reviewed this in light of the recent performance improvements of the Javascript engines.
Personally I use push frequently. Most of the time readability and maintainability is more important than performance, at least when the performance impact is small enough. The performance tests posted in the answers here show that the performance difference between various methods isn't very big.
Very often when I'm pushing an object into an array, I want the reference to that object to be returned to me. For example:
// Returns object
function createAndAdd(arr) {
return arr[arr.length] = { id: 1 };
}
var obj = createAndAdd(arr);
Now I have the new object and I've added it to an array. If I'd used push then I would have been returned the length of the array. It would look like the following:
function createAndAdd(arr) {
var obj = { id: 1 };
arr.push(obj);
return obj;
}
or even uglier, especially if the object gets big:
function createAndAdd(arr) {
return arr[arr.push({ id: 1 }) -1];
}
Personally, I love functions with immediate return statements. Keeps it simple and easy to look at. Love the question. Thanks for asking it.
It's a way to limit nested braclets. If you have enough of them you cant see howmany there are or howmany you need (when later looking at the code). I would use a var, one should only have to count things one time.
bar = foo.length;
foo[ bar++ ] = "new item 0";
foo[ bar++ ] = "new item 1";
foo[ bar++ ] = "new item 2";
foo[ bar++ ] = "new item 3";
http://jsfiddle.net/vEUU3/
I think its not about performance, or at least is not such a big deal... what really matters here is declarative way vs imperative way.
Array.prototype.push method returns the updated array's length while the direct declaration returns the value that is being assigned. That's the only difference I see, but I usually read some best-practices recommendations about the push method being a better way to assign new values to an array.
Some coders don't recommend to use array.push() cause it modify the principal object. Instead of push(), you could use the spread operator:
let arrayOne = [1, 2, 3, 4];
let arrayTwo = arrayOne;
arrayTwo.push(5);
console.log(arrayOne);
console.log(arrayTwo);
// equals to arrayOne before the push()
let arrayOneAux = [1, 2, 3, 4];
// spread operator
let arrayThree = [...arrayOneAux, 5];
console.log(arrayOneAux);
console.log(arrayThree);
What are the downsides to doing:
var myArray = [];
myArray[myArray.length] = val1;
myArray[myArray.length] = val2;
instead of:
var myArray = [];
myArray.push(val1);
myArray.push(val2);
I'm sure the push method is much more "acceptable", but are there any differences in functionality?
push is way faster, almost 300% faster.
Proof: http://jsperf.com/push-vs-length-test
Since arrays in JavaScript do not have holes the functionality of those two methods is equal. And yes, using .push() is much cleaner (and shorter).
I've generally thought length assignment was faster. Just found Index vs. push performance which backs that up; for my Chrome 14 browser anyway, over a single test run. However there is not much in it in Chrome.
There seems to be discrepancy on which test is faster among the varying JavaScript engines. The differences in speed may be negligible (unless an unholy amount of pushes are needed). In that case, the prudent developer should always err on the side of readability. In this case, in my opinion and the opinion of #TheifMaster is that [].push() is cleaner and it is easier to read. Maintenance of code is the most expensive part of coding.
As I tested, the first way is faster, I'm not sure why, keep researching. Also the ECMA doesn't mentioned which one is better, I think it is depending on how the browser vendor implements this.
var b = new Array();
var bd1 = new Date().getTime();
for(var i =0;i<1000000; i++){
b[b.length] = i;
};
alert(new Date().getTime()- bd1);
var a = new Array();
var ad1 = new Date().getTime();
for(var i =0;i<1000000; i++){
a.push(i);
};
alert(new Date().getTime()- ad1);
In JS there are 3 different ways you can add an element to the end of an array. All three have their different use cases.
1) a.push(v), a.push(v1,v2,v3), a.push(...[1,2,3,4]), a.push(..."test")
Push is not a very well thought function in JS. It returns the length of the resulting array. How silly. So you can never chain push() in functional programming unless you want to return the length at the very end. It should have returned a reference to the object it's called upon. I mean then it would still be possible to get the length if needed like a.push(..."idiot").length. Forget about push if you have intentions to do something functional.
2) a[a.length] = "something"
This is the biggest rival of a.push("something"). People fight over this. To me the only two differences are that
This one returns the value added to the end of the array
Only accepts single value. It's not as clever as push.
You shall use it if the returned value is of use to you.
3. a.concat(v), a.concat(v1,v2,v3), a.concat(...[1,2,3,4]), a.concat([1,2,3,4])
Concat is unbelievably handy. You can use it exactly like push. If you pass the arguments in array it will spread them to the end of the array it's called upon. If you pass them as separate arguments it will still do the same like a = a.concat([1,2,3],4,5,6); //returns [1, 2, 3, 4, 5, 6] However don't do this.. not so reliable. It's better to pass all arguments in an array literal.
Best thing with concat is it will return a reference to the resulting array. So it's perfect to use it in functional programming and chaining.
Array.prototype.concat() is my preference.
4) A new push() proposal
Actually one other thing you can do is to overwrite the Array.prototype.push() function like;
Array.prototype.push = function(...args) {
return args.reduce(function(p,c) {
p[p.length] = c;
return p
}, this)
};
so that it perfectly returns a reference to the array it's called upon.
I have an updated benchmark here: jsbench.me
Feel free to check which is faster for your current engine. arr[arr.length] was about 40% faster than arr.push() on Chromium 86.
I've been reading, and they're saying that associative arrays won't give you the same efficiency as arrays. An associative array can look things up in O(N) time, where an array can look things up in O(1).
Here's my question: which one would be more efficient in terms of looking up values quickly and not hogging too much memory?
Associative:
var myVars=new Array();
myVars['test1'] = a;
myVars['test2'] = b;
myVars['test3'] = c;
... (up to 200+ values)
echo myVars['test2'];
Stored Associative:
var myVars=new Array();
var TEST1 = 1;
var TEST2 = 2;
var TEST3 = 3;
... (up to 200+ values)
myVars[TEST1] = a;
myVars[TEST2] = b;
myVars[TEST3] = c;
... (up to 200+ values)
echo myVars[TEST2];
First, the first usage of Array is wrong. Although it is possible to do it, it does not mean you should. You are "abusing" the fact that arrays are objects too. This can lead to unexpected behaviour, e.g. although you add 200 values, myVars.length will be 0.
Don't use a JavaScript array as associative array. Use plain objects for that:
var myVars = {};
myVars['test1'] = a;
myVars['test2'] = b;
myVars['test3'] = c;
Second, in JavaScript there is no real difference between the two (objects and arrays). Arrays extend objects and add some behaviour, but they are still objects. The elements are stored as properties of the array.
You can find more information in the specification:
Array objects give special treatment to a certain class of property names. A property name P (in the form of a String value) is an array index if and only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal to 232−1. (...)
So both:
var obj = {'answer': 42};
obj['answer'];
and
var arr = [42];
arr[0];
have the same access time†, which is definitely not O(n).
†: It is better to say should have. Apparently this varies in different implementations.
Apart from that, your second example is horrible to maintain. If you assign numbers to variables, why not use the numbers directly?
var myVars = [];
myVars[0] = a;
myVars[1] = b;
myVars[2] = c;
Update:
More importantly: You have to choose the right data structure for your needs and this is not only determined by the access time of a single element, but also:
Are the keys consecutive numbers or arbitrary strings/numbers?
Do you have to access all (i.e. loop over all) elements of the collection?
Numerical arrays (arrays) and associative arrays (or hash tables/maps (objects in JS)) provide different solutions for different problems.
I posit that the present responses do not fully consider more practical use cases. I created this jsperf to demonstrate. While #Felix's jsperf demonstrates lookup speed, it's not performed on sufficiently large objects to be really useful. I think 10,000 simple properties is more reasonable. Further, you need to randomly select keys in the sequence to read, modify, delete and create to truly demonstrate the performance differences between the two types.
First of all, whoever they are, feel free to ignore them.
Every decent implementation of every decent scripting language, including JavaScript, will give you associative arrays that are either O(log(n)) access time, or else O(1) average access time, O(n) worst case (which you almost never hit). Either way in practice a lookup is fast.
Arrays have O(1) guaranteed access time, which is incredibly fast. But in some scripting languages (eg PHP) there isn't even a native array type provided. They just use associative arrays for both.
Answer: test it out yourself.
Update: After some back-and-forth with Felix, it appears that array access is usually faster than both associative arrays and objects. This is not always the case, notably in Chrome. In Chrome 11 on Ubuntu 11, arrays are faster. In Chrome 11 on Mac OS 10.6 there is no notable difference between them.
These tests did not measure manipulation, only reading.
Namely, how does the following code:
var sup = new Array(5);
sup[0] = 'z3ero';
sup[1] = 'o3ne';
sup[4] = 'f3our';
document.write(sup.length + "<br />");
output '5' for the length, when all you've done is set various elements?
My 'problem' with this code is that I don't understand how length changes without calling a getLength() or a setLength() method. When I do any of the following:
a.length
a['length']
a.length = 4
a['length'] = 5
on a non-array object, it behaves like a dict / associative array. When I do this on the array object, it has special meaning. What mechanism in JavaScript allows this to happen? Does JavaScript have some type of property system which translates
a.length
a['length']
into "get" methods and
a.length = 4
a['length'] = 5
into "set" methods?
Everything in JavaScript is an object. In the case of an Array, the length property returns the size of the internal storage area for indexed items of the array. Some of the confusion may come into play in that the [] operator works for both numeric and string arguments. For an array, if you use it with a numeric index, it returns/sets the expected indexed item. If you use it with a string, it returns/sets the named property on the array object - unless the string corresponds to a numeric value, then it returns the indexed item. This is because in JavaScript array indexes are coerced to strings by an implicit toString() call. Frankly, this is just one more of those things that makes you scratch your head and say "JavaScript, this, this is why they laugh at you."
The actual underlying representation may differ between browsers (or it may not). I wouldn't rely on anything other than the interface that is supplied when working with it.
You can find out more about JavaScript arrays at MDN.
Characteristics of a JavaScript array
Dynamic - Arrays in JavaScript can grow dynamically .push
Can be sparse - for example, array[50000] = 2;
Can be dense - for example, array = [1, 2, 3, 4, 5]
In JavaScript, it is hard for the runtime to know whether the array is going to be dense or sparse. So all it can do is take a guess. All implementations use a heuristic to determine if the array is dense or sparse.
For example, code in point 2 above, can indicate to the JavaScript runtime that this is likely a sparse array implementation. If the array is initialised with an initial count, this could indicate that this is likely a dense array.
When the runtime detects that the array is sparse, it is implemented in a similar way to an object. So instead of maintaining a contiguous array, a key/value map is built.
For more references, see How are JavaScript arrays implemented internally?
This really depends on what you intend to do with it.
[].length is "magical".
It doesn't actually return the number of items in the array. It returns the largest instated index in the array.
var testArr = []; testArr[5000] = "something"; testArr.length; // 5001
But the method behind the setter is hidden in the engine itself.
Some engines in some browsers will give you access to their implementations of those magic-methods.
Others will keep everything completely locked down.
So don't rely on defineGetter and defineSetter methods, or even, really, __proto__ methods, unless you know which browsers you know you're targeting, and which you aren't.
This will change in the future, where opt-in applications written in ECMAScript Next/6 will have access to more.
ECMAScript 5-compliant browsers are already starting to offer get and set magic methods in objects and there's more to come... ...but it's probably a while away before you can dump support for oldIE and a tonne of smartphones, et cetera...
It is important to know that when you do sup['look'] = 4; you are not using an associative array, but rather modify properties on the object sup.
It is equivalent to sup.look = 4; since you can dynamically add properties on JavaScript objects at any time. sup['length'] would for an instance output 5 in your first example.
To add to tvanfosson's answer: In ECMA-262 (the 3.0 specification, I believe), arrays are simply defined as having this behavior for setting properties (See 15.4.5.1). There's no general mechanism underlying it (at least as of now) - this is just how it's defined, and how JavaScript interpreters must behave.
As other people have mentioned, a property in JavaScript can basically act as both as getter and a setter of your array (or string or other inputs).
As a matter of fact, you might try this yourself:
const test = [1, 2, 3, 4, 5]
test.length = 3
console.log(test) // [1, 2, 3]
test.length = 5
console.log(test) // Guess what happens here!
As far as I know, arrays in JavaScript do not work exactly like associative arrays and you have elements which are put in memory as contiguously as possible (given that you can have arrays of mixed objects), depending on the JavaScript engine you are considering.
As a side note, I am a bit baffled that the most voted answer keeps spreading the over-simplified myth (or half-truth) of "everything being an object in JavaScript"; that is not exactly true, otherwise you will never study primitives, for example.
Try to do this:
const pippi = "pippi"
pippi.cat = "cat"
console.log(pippi.cat) // Will it work? Throw an error? Guess why again
Spoiler: the string is wrapped in a throwaway object for that specific operation on the second line, and then in the following one you are just going to access a property of the primitive which is not there (provided you did not play with String.prototype or the like), so you get undefined.
Array object inherits caller, constructor, length, and name properties from Function.prototype.
A JavaScript array is an object just like any other object, but JavaScript gives it special syntax.
arr[5] = "yo"
The above is syntactic sugar for
arr.insert(5,"yo")
which is how you would add stuff to a regular object. It's what is inside the insert method that changes the value of arr.length
See my implementation of a customArray type here: http://jsfiddle.net/vfm3vkxy/4/