Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does "(M[key] || (M[key] = [])).push(elem); " work?

Tags:

javascript

I know that

(M[key] || (M[key] = [])).push(elem);

is a common way to solve the common problem

"Push this element to the end of array if the array exists, and if it doesn't exist, initialize the array and then push the element"

But how does the syntax break down? Here's how I see it:

The presence of the || means that whatever is to the left and right of that operator is interpreted as a boolean. Therefore M[key] and (M[key] = []) are either booleans are statements that are cast into booleans. In either case, I don't see how one can push onto the value of (M[key] || (M[key] = []). What the Hell is going on here?

like image 329
Subpar Web Dev Avatar asked Oct 19 '22 18:10

Subpar Web Dev


1 Answers

This is indeed a very common pattern in JavaScript.

You need to add an element to the list associated to the key, creating a new list if one doesn't exist.

To get the list associated to a key the code is:

M[key]

but this returns undefined if the key is not present.

Javascript || (logical-or) operator has a quite useful semantic: if the left-side is true then return it, otherwise evaluate and return the right side. The expression:

M[key] || (M[key] = [])

therefore returns the list associated with M[key], if present, otherwise the part (M[key] = []) is evaluated. This works because an array (even when empty) is true in JavaScript and undefined is false.

The assignment operator = (which is a normal operator in JavaScript and can be used in the middle of expressions) performs the assignment then returns the value it just assigned.

The whole thing thus just returns the list associated with the key or creates a new empty list if the key was unknown in M.

Pushing an element to an array is <array>.push(x) and the part to the left of the dot can be any expression.

(M[key] || (M[key] = [])).push(x);

therefore will add x to the list returned by the left-hand expression.

The "expanded version would look like this:

if (!M[key]) {
    M[key] = [];
}
M[key].push(x);

Beware that using objects as dictionaries in JavaScript requires some care because of inherited members. For example with M = {} and key = "constructor" that code would fail.

like image 97
6502 Avatar answered Oct 31 '22 20:10

6502