简体   繁体   中英

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

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?

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.

The || is a short-circuit operator. This means if the first half is "truthy" it never does the second half. So if M[key] has a value (a truthy value) that's the value used and we are done. Otherwise the 2nd part gets done.

Written out long form, you might have:

   if (M[key]) M[key].push(elem);
   else {
       M[key] = [];
       M[key].push(elem);
   }

So you can see why the shorter idiom developed.

Use your order of operations! Follow the parenthesis.

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

Break it down. (M[key] || (M[key] = []))

The || is the OR operator. So if M[key] exists, push the new element to it. If not, create the array and add it.

It evaluates to a truthy comparison. (true OR else)

Ok there are many things going on here.

First of how arrays work in javascript. You can access or assign an array element using the ARRAY_NAME[KEY_VALUE].

Thus M[Key] will return the object if it exists.

Based on this code M is array of arrays. So when M[Key] evaluates it will return an array or null.

When the expression a || b is evaluated in javascript it is short circuited and is also evaluated left to right -- that is if a is true b is never evaluated -- if a is false then b is evaluated. ( This is common in many C like languages. )

Since M[Key] will return the object if it exists the part after the || is never evaluated and the array at the that key is used to push the new elem.

If nothing exists at M[Key] then the b part is evaluated and the b part in this case first assigns the empty array ( [] ) to the location at M[Key] (as we noted before M[Key] can be used for assignment too) This new empty array is then used (since it is the result of evaluating the expression inside the () ) to push the new elem.

https://en.wikipedia.org/wiki/Short-circuit_evaluation

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array

I understad this following way: undefined in javascript as boolean is false.

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

is executed following way: if M[key] is not undefined - false, result of the expression is M[key].

if M[key] is undefined - false, the second part of boolean ||-OR operator is executed and M[key] gets empty array as a value. Result of the expression is M[key], but now it has empty array as a value.

Afterwards we push new value into M[key] array: M[key].push(elem);

I think this is useful javascript-operators-and-truthy-falsy

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM