0

The code snippet is:

var a = 'foo'
a || a = 'bar'

What I expected is that it can work normally which means a will be 'bar' finally.But I got an error

Uncaught SyntaxError: Invalid left-hand side in assignment.

According to the error,I thought maybe it is something wrong with the left hand side expression a || a.It seems that a || a is invalid here.But why?I turn to ecmascript language specification for help.In 12.15.1 Static Semantics: Early Errors, I find:

It is an early Reference Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType of LeftHandSideExpression is invalid.

So, the AssignmentTargetType of LeftHandSideExpression a||a is invalid.But I am confused why a||a 's AssignmentTargetType is invalid.About this,the specification just said:

12.15.3 Static Semantics: AssignmentTargetType

AssignmentExpression:

YieldExpression

ArrowFunction

AsyncArrowFunction

LeftHandSideExpression = AssignmentExpression

LeftHandSideExpression AssignmentOperator AssignmentExpression

  1. Return invalid.

I can't figure out why a||a 's AssignmentTargetType is invalid based on what is given.

My question is: Why a||a = 'bar' will get a reference error in javascript?If it is something with invalid AssignmentTargetType of LeftHandSideExpression,why a||a is invalid?

Chor
  • 833
  • 1
  • 5
  • 14
  • The left side of a `=` must be a single identifier, or valid destructuring target – CertainPerformance Feb 18 '20 at 06:32
  • Does this answer your question? [What's a valid left-hand-side expression in JavaScript grammar?](https://stackoverflow.com/questions/3709866/whats-a-valid-left-hand-side-expression-in-javascript-grammar) – Markus Dresch Feb 18 '20 at 06:34
  • What did you expect the expression to do? – Teemu Feb 18 '20 at 06:45
  • @Teemu `a` will became 'bar' – Chor Feb 18 '20 at 06:46
  • @Chor Interesting. The value of `a` is `"foo"`, and logical OR returns the value of one of its operands, in this case I'd expect "foo" = "bar", which wouldn't make much of sense ..? – Teemu Feb 18 '20 at 06:52
  • @Teemu According to what you said,logical OR returns the value of one of its operands.So `undefined || undefined` will still return `undefined` and thus `undefined || indefined = 'bar'` will become `undefined = 'bar'`,right?But the result of the former is different from that of the latter. – Chor Feb 18 '20 at 07:13
  • How is it different? [`undefined`](https://developer.mozilla.org/en-US/docs/Glossary/undefined) is a primitive value as well as a string. – Teemu Feb 18 '20 at 07:17
  • @Teemu I mean since the former(`undefined || undefined = 'bar' `) is the same as the latter(`undefined = 'bar' `),their results will be the same.But in fact,the former get an error while the latter will work normally. – Chor Feb 18 '20 at 07:21
  • You didn't read what it is said about [undefined](https://developer.mozilla.org/en-US/docs/Glossary/undefined). "_undefined is a property of the global object. That is, it is a variable in global scope. The initial value of undefined is the primitive value undefined._" If you just write `undefined = 'bar';` then you assign to the global var, but logical OR returns the primitive, not a reference. You need a reference at the left-hand side. – Teemu Feb 18 '20 at 07:31
  • I suppose your problem is covered in the [Assignment operators](https://www.ecma-international.org/ecma-262/10.0/index.html#sec-assignment-operators) section of the standard, where you can find a link to [Destructuring Assignment](https://www.ecma-international.org/ecma-262/10.0/index.html#sec-destructuring-assignment). – Teemu Feb 18 '20 at 08:09

3 Answers3

3

My question is: Why a||a = 'bar' will get a reference error in javascript?

It's not a reference error but a syntax error. That means the code you have written cannot be parsed into a valid program.

If it is something with invalid AssignmentTargetType of LeftHandSideExpression,why a||a is invalid?

It's much simpler than that: The syntax of an assignment expression, among other things, is

LeftHandSideExpression = AssignmentExpression

That means on the left side of the = we need a LeftHandSideExpression.

|| is a LogicalORExpression but not a LeftHandSideExpression and therefore it cannot appear in this position.

You can think of the different types of expressions being organized in a hierarchy (I simplified the following example by leaving out some type of expressions):

AssignmentExpression
         ^
         |
LogicalORExpression
         ^
         |
LeftHandSideExpression
         ^
         |
PrimaryExpression
         ^
         |
Identifier Reference

That is: An Identifier Reference is a PrimaryExpression is a LeftHandSideExpression, etc.

LogicalORExpression is higher up in the hierarchy which makes it a superset that includes LeftHandSideExpression. That means there are some expressions, such as ||, which are a LogicalORExpression but not a LeftHandSideExpression.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • I'm don't see how a `LeftHandSideExpression` can be a `LogicalORExpression` but not the other way round? – Leon Segal Feb 18 '20 at 09:59
  • @LeonSegal: Maybe I did not express this clearly: Since `LogicalORExpression` is a superset that includes `LeftHandSideExpression`, some `LogicalORExpression` are `LeftHandSideExpression` but not all. `||` is one of those. I updated the wording. – Felix Kling Feb 18 '20 at 10:05
  • I think I am still confused. `LogicalORExpression` is contained in `LeftHandSideExpression`, but also, an or statement can't be used in a left hand side expression? – Leon Segal Feb 18 '20 at 10:10
  • @LeonSegal: No, `LogicalORExpression` is not contained in `LeftHandSideExpression` it's the other way round. – Felix Kling Feb 18 '20 at 10:11
  • That's still confusing to me - `LeftHandSideExpression` is contained in `LogicalORExpression` so `LeftHandSideExpression` is a `LogicalORExpression` but you can't actually use an or statement in a left hand expression, even though a left hand expression is an or statement? I will have to learn how to read the spec I think. – Leon Segal Feb 18 '20 at 10:27
  • @LeonSegal: `LogicalORExpression` is a **superset**. It contains all the same expressions that `LeftHandSideExpression` **plus** `||`. `||` is **not** a `LeftHandSideExpression`. It should be relatively clear by looking at what valid `LeftHandSideExpression`s are: https://www.ecma-international.org/ecma-262/10.0/#sec-left-hand-side-expressions . A `LogicalORExpression` is either a `LogicaANDExpression` or `LogicalORExpression || LogicalAndExpression`. – Felix Kling Feb 18 '20 at 10:31
  • The spec is not clear to me - I will have to spend some time learning to read it (I did post that). Thanks for clearing up about the superset logic though. – Leon Segal Feb 18 '20 at 10:40
  • @FelixKlingFe " || is a LogicalORExpression but not a LeftHandSideExpression and therefore it cannot appear in this position." Which are valid LeftHandSideExpression?I can't find that in spec. – Chor Feb 18 '20 at 13:46
  • @Chor: https://www.ecma-international.org/ecma-262/10.0/#sec-left-hand-side-expressions lists them. – Felix Kling Feb 18 '20 at 14:02
2

JavaScript will execute from left to right. a || a will evaluate to foo before you try re-assigning a new value to a. That means you're trying to run 'foo' = 'bar' which leads you to your invalid left hand assignment error.

  • Is this right? I thought || in js evaluated to the first operand if the first operand is true or the second operand if the first operand is false? So i.e. in this case 'foo'. Wouldn't this make the statement 'foo' = 'bar', which would error as strings are immutable? – Leon Segal Feb 18 '20 at 06:48
  • According to what you said,`undefined || indefined = 'bar'` will also become `undefined = 'bar'`,right?So the result of the former is the same as that of the latter.But in fact,the former will get an error while the assignment of the latter will succeed and doesn't get any error. – Chor Feb 18 '20 at 06:52
  • @LeonSegal I left quotes off of foo, so I edited to update. We're saying the same thing. It never makes it past the first operand and evaluates to `'foo' = 'bar'` – shapirowned Feb 18 '20 at 06:55
  • @Chor no, that's incorrect - `undefined` is a falsy value and will not pass the first operand – shapirowned Feb 18 '20 at 06:59
  • @shapirowned Even in this case,`undefined || undefined` will still return `undefined`.So `undefined || indefined = 'bar'` will also become `undefined = 'bar'` – Chor Feb 18 '20 at 07:07
  • @Chor `undefined || indefined` will error out at `indefined` because you're trying to reference a variable that doesn't exist. Regardless, as others have said you shouldn't pursue assigning a variable in this manner. – shapirowned Feb 18 '20 at 07:11
  • " reference a variable that doesn't exist".However,`undefined` is a global property of the global object,It always exists.You can try output `undefined in window`. – Chor Feb 18 '20 at 07:16
  • Also, it should be noted that js does not evaluate left to right. It has operator precedence https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence which means `||` will be evaluated before `=`. – Leon Segal Feb 18 '20 at 09:16
1

Update: As @Teemu pointed out. Updated the comments.

var a = 'foo'
a || a = 'bar' // a || a evaluates to 'foo', So it will be `'foo' = 'bar'` here

a || (a = 'bar') // will result to a is 'foo'

a = ''
a || (a = 'bar') // will result to a is 'bar'
Siva K V
  • 10,561
  • 2
  • 16
  • 29