The internal reference value for a.x — the "target" of the assignment a.x = a — is calculated before the assignments happen. The target of the assignment is therefore the "x" property on the old value of a, which is the same as b. The new value of a doesn't have an "x" property, so that's undefined. However, the assignment gave an "x" property to the old value of a, which is the current value of b.
If you like "language lawyering", you can see a description here in the ES2015 spec for the = operator and how it works. Note that in step 1, something called lref is determined. That's the "target" I mentioned in the above paragraph, and note that it happens before the right-hand "assignment expression" is computed.