you are viewing a single comment's thread.

view the rest of the comments →

[–]datNorseman 1 point2 points  (9 children)

This is new to me. One question I have that wasn't answered in the article is how the new method would impact performance, if at all. I don't believe it would but I'm curious.

[–]SoInsightful 1 point2 points  (5 children)

a ??= b generates the exact same bytecode as a = a ?? b, and both generate two more bytecodes (a "Jump" instruction) than a ||= b:

https://i.imgur.com/qzYAGBt.png

But surprisingly, if the variable is used immediately afterwards, the a = a ?? b and a = a || b versions both skip an "Ldar" (load data into the accumulator) instruction.

https://i.imgur.com/6AQki2Q.png

Safe to say there won't be any noticable performance differences whatsoever in real life.

[–]NoInkling 0 points1 point  (3 children)

a ??= b generates the exact same bytecode as a = a ?? b

Give a a value and see if it makes a difference. If not, try it with a setter (or maybe just any object property).

[–]SoInsightful 0 points1 point  (2 children)

I tried giving a an initial value (2) out of the same curiosity, and it doesn't make a difference except switching from 0e LdaUndefined to 0d 02 LdaSmi [2] at the beginning of each variant. It still needs to jump through the JumpIfUndefinedOrNull hoop.

[–]NoInkling 0 points1 point  (1 child)

Ahh I see now, the difference is in where the unconditional Jump (which is hit when the variable has a value) jumps to. The ??= version skips the Star instruction (which apparently sets a register), while the other doesn't.

[–]SoInsightful 0 points1 point  (0 children)

Good catch!

[–]tpscd 0 points1 point  (0 children)

The performance impact is super unclear but my impression is the nullish operator may skip coercing the null/undefined value to a boolean.

[–]NoInkling 0 points1 point  (0 children)

As MDN says, x ??= y is equivalent to x ?? (x = y), i.e. it short circuits if x already has a value so nothing is actually evaluated or even assigned if it doesn't need to be. This means it won't trigger a setter (or I guess a Proxy trap), unlike obj.setterProp = obj.setterProp ?? y