Zze Zze - 25 days ago 7
Javascript Question

Why is this an invalid assignment left hand side?

Why can I do the following operations:



var b1, b2;

b1 = b2 = true;

document.write(b1," ", b2);
document.write("<br>");

b1 = !b2;

document.write(b1," ", b2);
document.write("<br>");

b1 = b2 = !true;

document.write(b1," ", b2);





Yet when I try the following operations I recieve a
ReferenceError: invalid assignment left-hand side
?



var b1, b2;

b1 = !b2 = true;

document.write(b1," ", b2);





It's obvious that I can't do this, but I can't find an explanation as to why I can't. The MDN developer guide for the error states:


There was an unexpected assignment somewhere. This might be due to a mismatch of a assignment operator and a comparison operator, for example. While a single "=" sign assigns a value to a variable, the "==" or "===" operators compare a value.


All of the assignment operators work individually as proven, so why can't this be combined into a singular operation?

Answer

When you try to do this:

var b1, b2;

b1 = !b2 = true;

document.write(b1, " ", b2);

You are basically doing (they are functionally equivalent):

var b1, b2;

!b2 = true;
b1 = b2;

document.write(b1, " ", b2);

In the line !b2 = true, you are trying to assign an expression (the left side) to a value - that makes absolutely no sense. To break it down, you are trying to do true = true. This is because ! takes precedence over =, so it's like this:

  • b2 is undefined when we do !b2, so !undefined is true because undefined is falsy.
  • !b2 = true is basically doing true = true because !b2 is true as mentioned earlier.

If you want to understand the syntax and semantics, you can delve into the ECMAScript® 2015 Language Specification:

Section 12.14.1 - Assignment Operators - Static Semantics: Early Errors

AssignmentExpression : LeftHandSideExpression = AssignmentExpression

  • It is an early Reference Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget of LeftHandSideExpression is false.

Where IsValidSimpleAssignmentTarget is:

Section 12.14.3 - Assignment Operators - Static Semantics: IsValidSimpleAssignmentTarget

AssignmentExpression :
  YieldExpression
  ArrowFunction
  LeftHandSideExpression = AssignmentExpression
  LeftHandSideExpression AssignmentOperator AssignmentExpression

1. Return false.

Now look back at your code: b1 = !b2 = true. b1 = !b2 is fine because it is LeftHandSideExpression = AssignmentExpression, thus returning true for IsValidSimpleAssignmentTarget. The problem arises when we check !b2 = true. If we look at the definition of LeftHandSideExpression:

Section 12.3 - Left-Hand-Side Expressions

Syntax

LeftHandSideExpression :
  NewExpression
  CallExpression

(You can view the definitions of NewExpression and CallExpression in the specification link above)

You can see that !b2 = true is not a valid AssignmentExpression, as it does not fit the criteria LeftHandSideExpression = AssignmentExpression. This is because !b2 is not a valid LeftHandSideExpression, thus IsValidSimpleAssignmentTarget returns false, throwing the ReferenceError.


You can combat this by doing:

b1 = !(b2 = true);

Using parentheses, inside the parentheses takes precedence over outside. That way, b2 is assigned, and since it is true, inside the parentheses evaluates to true. Next, it's equivalent to:

b1 = !(true);

As inside the parentheses is evaluated to true as mentioned above. b1 will be the opposite of b2 as expected, and b2 will be true.


Otherwise known as order of operations. Further reading: https://en.wikipedia.org/wiki/Order_of_operations