Using the push method or .length when adding to array? - javascript

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.

Related

Array.from vs Array.prototype.map

So what is the difference between this two functions?
They both create new Array object. Only difference I found so far is that Array.from supports ArrayLike parameters. I don't see any reason why they just haven't added ArrayLike support for Array.prototype.map function.
Am I missing something?
The purpose of Array.from() is to take a non-array (but array-like) object and make a copy of it into an actual array. This then allows you to use ALL array methods on the copy including things beyond just iterating it such as .splice(), .sort(), .push(), .pop(), etc... which is obviously much more capable than just make .map() work with array-like things.
Array.map seems to be a bit more performant as well:
var a = () => [{"count": 3},{"count": 4},{"count": 5}].map(item => item.count);
var b = () => Array.from([{"count": 3},{"count": 4},{"count": 5}], x => x.count);
var iterations = 1000000;
console.time('Function #1');
for(var i = 0; i < iterations; i++ ){
b();
};
console.timeEnd('Function #1')
console.time('Function #2');
for(var i = 0; i < iterations; i++ ){
a();
};
console.timeEnd('Function #2')
Running this code using Chrome (Version 65.0.3325.181) on this page gave me the follow results:
Function #1: 520.591064453125ms
Function #2: 33.622802734375ms
Static method vs instance method
I know a lot of time has passed since the question was asked. A lot of good things have been said. But I would like to add some more. If we try to determine the nature of the two methods we can say that Array.from
has no relation to any instance of Array. It is static method like Array.isArray or Array.of. You also have static properties like length for the Array object. As a static method Array.from can not be Called from instance.
For example:
var indexes=[0,1,2,3]
index.from()
>>> index.from is not a function
In the other hand if you write
Array.map() you will end up with a Array.map is not a function. It is because Array.prototype.map Exist for the instance of array. In our little example indexes is an instance of Array then we use map on it.
Example
var indexes=[0,1,2,3]
function doubleIt(x){
return 2*x;
}
indexes.map(doubleIt);
With array.from it shoud be something like
Array.from(indexes, doubleIt)
I used quokka plugin on vscode to evaluate performance on vs code in a windows machine. It is not real case of performance benchmarking. But it can help to have an idea. I came up with the same conclusion as #rileynet map seem more performant but only for large array.
var N=10
var tabIndex=[ ...Array(N).keys()]
function doubleIt(x){
return 2*x;
}
tabIndex.map(doubleIt);/*?.*/ 0.040ms
Array.from(tabIndex, doubleIt)/*?.*/ 0.009ms
if N=100
tabIndex.map(doubleIt);/*?.*/ 0.052ms
Array.from(tabIndex, doubleIt)/*?.*/ 0.041ms
if N=1000
tabIndex.map(doubleIt);/*?.*/ 0.228ms
Array.from(tabIndex, doubleIt)/*?.*/ 0.339ms
if N=10000
tabIndex.map(doubleIt);/*?.*/ 2.662ms
Array.from(tabIndex, doubleIt)/*?.*/ 1.847ms
N=100000
tabIndex.map(doubleIt);/*?.*/ 3.538ms
Array.from(tabIndex, doubleIt)/*?.*/ 11.742ms
Making Array.prototype the prototype object for every single array-like "Class" in JS (more importantly, in DOM, where most of the 'array-like' objects live) would be a potential mistake.
What would a .reduce( ) on a list of HTML elements/attributes look like?
Array.from is the official version of [].slice.call(arrayLike); with the added benefit of not having to create an unused array, just to create an array.
So really, Array.from can be polyfilled with function (arrLike) { return [].slice.call(arrLike); }, and minus native-implementation speed/memory improvements, it's the same result.
This has little to do with map|reduce|filter|some|every|find, which are the keys to living a long and happy life, without the need of micromanaging loops to get things done.

What use cases are there in JavaScript for Sparse Arrays?

What possible programming use could you have where a sparse array would be better than an (regular) object?
By sparse array I mean one where:
arr = []; //Initialize
arr[0] = 'W';
arr[1] = 'T';
arr[3] = 'F';
console.log(arr[0] !== undefined) //true
console.log(arr[1] !== undefined) //true
console.log(arr[2] === undefined) //true
console.log(arr[3] !== undefined) //true
Or more formally:
An object, O, is said to be sparse if the following algorithm returns true:
1. Let len be the result of calling the [[Get]] internal method of O with argument
"length".
2. For each integer i in the range 0≤i<ToUint32(len)
a. Let elem be the result of calling the [[GetOwnProperty]] internal method of O
with argument ToString(i).
b. If elem is undefined, return true.
3. Return false.
ECMA 262 5.1 - 15.4 Array Objects
Moreover, the ECMA 262 5.1 Standard further defines length specifically as:
The length property of this Array object is a data property whose value is always numerically greater than the name of every deletable property whose name is an array index.
So the example above, arr.length === 4 despite there only being three elements defined.
In fact, according to the standard, any Number greater than 3 is a valid length for arr, including Math.PI.
Consequently, does this mean that no one should use:
for(var i=0; i<arr.length; i++)
//Cannot trust arr[i] exists
and instead it would be more appropriate to use
for(key in arr)
//Always exists
I've never encountered an intentional one in the wild, and really only began thinking about it while reading an odd Q&A here, and now I'm a little unsettled.
I've long known that there's not a neat way to remove an element from an Array, but now I'm even more confused as to why you would intentionally leave a hole, let alone define a standard where length can be any number greater than the last defined element.
If I wanted random key value pairs, I'd use an Object. If I want to be able to cleanly iterate, I use an Array. Am I missing something?
Note, I'm looking for a specific use case, or a class of generalized use cases not a reference to the standards, or an opinion. I know it's allowed, and I already have an opinion. :)
To add a test or see some of the ones I've seen where the Array standard works in unexpected ways, check out this fiddle
Sorry if this is a bit abstract. Been thinking about it all night.
One possible use-case for sparse arrays that I've come across in real usage is for a heat-map.
Start with your map being an empty array of X × Y elements. Load your data, and populate it into the map by incrementing the array elements at the relevant co-ords.
Another similar example might be a battleship game, where boats are placed into an empty grid by populating the array elements at the appropriate co-ordinates.
That's not to say this is this only way to do this, or even the best way -- both examples can quite easily be achieved without using a sparse array -- but the question was asking for use cases, so there you go.
implementing the mathematical idea of 'sparse array' with JavaScript plain object ({}):
source={}
source[1000000] = 1; source[2000000]=2; source[3000000]=3
start = new Date();
target = (function(){
var ret = {};
Object.keys(source).forEach(function(key){
ret[key] = source[key]*source[key]
});
return ret
})();
end = new Date();
document.getElementById('runtime').textContent = end - start;
document.getElementById('result').textContent = JSON.stringify(target);
........................ result ..........................
<div id="result"></div>
...................... run time ..........................
<div id="runtime"></div>
implementing the mathematical idea of 'sparse array' with JavaScript array ([]):
source=[]
source[1000000] = 1; source[2000000]=2; source[3000000]=3
start = new Date();
target = source.map(function(u){ return u*u; });
end = new Date();
document.getElementById('runtime').textContent = end - start;
//document.getElementById('result').textContent = JSON.stringify(target);
console.log(target)
........................ result ..........................
<div id="result">see console</div>
...................... run time ..........................
<div id="runtime"></div>
The runtime is show to be zero in the first snippet (below what can be properly measured unless you run it repeatedly). In the 2nd snippet the runtime is about 100 milliseconds on my machine.
Would you like to "pay" for a little less typing with such differences in runtime? And if you don't do the things that have this horrible runtime (do you know what they are??) what remains then of the saved typing? the answer to the last question is: nothing.
{} is the correct choice. [] is the wrong choice. IMHO.
related question

Is there a reason JavaScript developers don't use Array.push()?

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);

Loop object properties vs numerically indexed array

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!

Javascript Array lookup efficiency: associative vs. stored associative?

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.

Categories