Zze - 4 months ago 24

Javascript Question

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
is neither an`LeftHandSideExpression`

nor an`ObjectLiteral`

and`ArrayLiteral`

`IsValidSimpleAssignmentTarget`

ofis false.`LeftHandSideExpression`

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`

You can see that `!b2 = true`

is not a valid * AssignmentExpression*, as it does not fit the criteria

`LeftHandSideExpression = AssignmentExpression`

`!b2`

is not a valid `LeftHandSideExpression`

`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}