Create array and push into it in one line

Javascript

Javascript Problem Overview


The following is just a theoretical JavaScript question. I am curious if the following can be converting into a single statement:

if(!window.foo){
  window.foo = [];
}
window.foo.push('bar');

everyone has probably written this code before, but can it be done in one line?
At first I thought something like this would work:

(window.foo || window.foo = []).push('bar');

but that doesn't work because of an invalid assignment. Next I tried chaining something on the push, but that doesn't work because push does not return the array.

Any thoughts on if this can be done in plain JavaScript?
(the result by the way should be that window.foo = ['bar'])

Javascript Solutions


Solution 1 - Javascript

You've got your assignment backwards*. It should be:

(window.foo = window.foo || []).push('bar');

The || operator in JavaScript does not return a boolean value. If the left hand side is truthy, it returns the left hand side, otherwise it returns the right hand side.

a = a || [];

is equivalent to

a = a ? a : [];

So an alternative way of writing the above is:

(window.foo = window.foo ? window.foo : []).push('bar');

* see comments for details

Solution 2 - Javascript

Your code works just fine if you add parentheses so that it does what you intended:

(window.foo || (window.foo = [])).push('bar');

Without the parentheses, it thinks that it should evaluate window.foo || window.foo first, and then assign the array to the result of that, which is not possible.

Solution 3 - Javascript

This question got me playing with different options for fun. It's too bad push returns the length instead of the original array reference, but for even shorter expressions it can be helpful to have something that can be immediately iterated, mapped, etc.

window.foo = (window.foo||[]).concat(['bar']); // always returns array, allowing:
(window.foo = (window.foo||[]).concat(['bar'])).forEach( ... )

(window.foo = window.foo||[]).push('bar'); // always returns length

window.foo && window.foo.push('bar') || (window.foo = ['bar']); // playing around

Solution 4 - Javascript

2021 Update

@zzzzBov's helpful answer,

(window.foo = window.foo || []).push('bar');

can be further simplified using the new ||= operator, logical OR assignment1,

(window.foo ||= []).push('bar');

1 See tcs39/proposal-logical-assignment, currently in Stage 4, and supported by major browsers.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmkoryakView Question on Stackoverflow
Solution 1 - JavascriptzzzzBovView Answer on Stackoverflow
Solution 2 - JavascriptGuffaView Answer on Stackoverflow
Solution 3 - JavascriptPlynxView Answer on Stackoverflow
Solution 4 - JavascriptkjhughesView Answer on Stackoverflow