Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Appending an element to an array: Differences between direct assignment and `push`? [closed]

arr.push(Math.random());

and

arr[arr.length]=Math.random();

have the same result.

So, what's the difference between them? In other words, when is it better to use the former than the latter?

like image 307
tic Avatar asked Mar 09 '23 14:03

tic


2 Answers

what's the difference between them

Looking at the specification and giving it some thought, there are at least six:

  1. push(...) is a method call, the other is an assignment.
  2. You can add multiple elements with push: arr.push(one, two, three). To do that with assignment, you need multiple assignments. (push also doesn't update length until it's done all the work, whereas naturally multiple assignments would update it for each assignment.)
  3. push checks to see if the array's length will become > 253-1 and throws a TypeError if so; assignment does not, it just happily creates a property with a name that isn't an array index. (It's an interesting check, given that array indexes are only allowed to be up to 232-1. But one the spec does in lots of places in relation to array length.)
  4. Since arr.push(...) looks up push on arr, it can be intercepted (by assigning a new push to arr or to Array.prototype). The assignment can only be intercepted on a per-property basis (using a setter for "0", "1", etc.) or via a Proxy.
  5. If you're working with a Proxy for an array with a set trap, rather than working with the array directly, you may observe different set calls (because the set trap will presumably set the value on the underlying array directly, and so you won't see the set for length).
  6. As Redu points out, the result of arr.push(value) is the new length of the array; the result of arr[arr.lenght] = value is the value pushed.

In other words, when is it better to use the former than the latter?

It's entirely up to you. Since push is a method call that ultimately ends up doing the same thing the assignment does (with a bit more overhead, such as the length check), then in theory on some engines or at least in some situations it may be the tiniest bit slower than direct assignment; but then, your direct assignment has the overhead of looking up arr.length. In practice, on modern engines, I see no significant difference; test here, and any difference would be extremely unlikely to matter in the real world anyway. Other than that and #2-#6 above, it's a style choice.

Example of #5 (only works on JavaScript engines with ES2015 Proxy support):

const a = [];
const p = new Proxy(a, {
  set(target, prop, value) {
    console.log("Proxy set called for " + prop + " = " + value);
    target[prop] = value;
    return true;
  }
});
p[0] = "a";         // We don't see length set here
console.log(p[0]);
p.push("b");        // We do here, because `push` sets `length` through
                    // the proxy reference
console.log(p[1]);
like image 155
T.J. Crowder Avatar answered Mar 12 '23 03:03

T.J. Crowder


In addition to T.J. Crowders detailed answer in real life my use of one or the other depends on one and only one factor. That's what return value i expect when i push an item to an array.

  • arr.push(item) returns you the new length of the array.
  • arr[arr.length] = item returns you pushed item.
  • arr.concat(item) returns you a new array with the pushed item.
  • (arr.push(item),arr) returns you the array with the newly pushed item.

In functional programming they both have their use cases. However especially the later two can introduce a huge difference and unexpected bugs to you code if you are not careful since in JS arrays are reference types.

Oh by the way since you have asked, unlike as mentioned in older books, the first two has zero effect on performance, even micro performance wise no difference can be seen anymore. They are both very fast.

like image 39
Redu Avatar answered Mar 12 '23 03:03

Redu