By mistake, I wrote:
++number++;
and got this:
Uncaught ReferenceError: Invalid left-hand side expression in prefix operation
Why? I would except this to to first increment number by one and then increment number by one again.
In JavaScript, ++ is both the prefix and postfix increment operator. The postfix operator has higher precedence, and so when we apply precedence, your expression becomes:
++(number++);
The result of number++ is a value, not a variable reference, and so it cannot be the operand of the prefix increment operator, for the same reason ++42 is invalid — there's nowhere to write the result back to.
Why does it call it the "left-hand side expression" when it's to the right of the operator? You'd have to look at the V8 source code (I can tell from the text of the error you're doing this on V8, probably Chrome). I can speculate that it's because many operators accept two operands (left and right), and that they just call the only operand to unary operators like ++ the "left-hand" by default. But that's speculation.
Related
According to Ecma-262, prefix increment and decrement operators are defined as:
UpdateExpression :
LeftHandSideExpression ++
LeftHandSideExpression ‐‐
++ UnaryExpression
‐‐ UnaryExpression
This is surprising, both that the postfix and prefix operators are defined in the same rule, and that it's ++ UnaryExpression when surely a unary expression in general is not actually a valid argument for the update operators.
It would seem cleaner and more logical to define the prefix increment and decrement operators in UnaryExpression itself, along with the other prefix operators, and other C syntax languages do this, e.g. the C standard section 6.5.3 defines unary-expression to include the prefix update operators along with the others.
Why does JavaScript define these operators the way it does?
Why does JavaScript define these operators the way it does?
It's mostly historical, as so many other oddities in the spec.
It would seem cleaner and more logical to define the prefix increment and decrement operators in UnaryExpression itself, along with the other prefix operators, and other C syntax languages do this
In fact, that's how it was defined for many years, in ES5.1 and ES6. It's simple, and has one syntactic production per precedence level (PostfixExpression being the next-tighter one), and was probably directly inherited from the C or Java grammar when JS was conceived.
Surely a unary expression in general is not actually a valid argument for the update operators
In C, -- -- x is actually valid, so that's why the prefix increment and decrement operator expressions contain another UnaryExpression. Of course, it would throw an exception when trying to evaluate the expression, but parsing it would work fine in ES5.
ES6 then added the concept of early errors, and increment and decrement operations now required a valid assignment target expression upon parsing. This was not encoded in the syntactical productions though.
It is surprising that the postfix and prefix operators are defined in the same rule
This definition is new in ES7. It changed with this commit that introduced the exponentiation operator, where the PostfixExpression was renamed to UpdateExpression and the prefix operators were moved into the rule. Some change like that was necessary because the ** operator allows an update expression, but not a UnaryExpression as its first argument (because unary minus, as in -x ** 3, was deemed too ambiguous).
(1) console.log(8*null)
// output to 0 ( null changes to 0)
(2) console.log("5"-1)
//output to 4 ("5" changes to 5)
(3) console.log("5"+1)
//output to "51" (1 changes to "1")
As if you see the above lines of code , some times type conversion happens on left hand side and some times it happens on right hand side of the binary operator.
So my question is how does JavaScript decides which operand type needs to be changed, does it happens internally (without in the knowledge of user) or is there any precedence of data type is there??
Because * is a multiplicative operator, it calls the specification's ToNumber abstract operation on both of its operands (first the left one, then the right one). The result of ToNumber(null) is 0 (see the link for a table), so 8 * 0 is 0.
Because - is a subtraction operator, it also calls ToNumber on its operands. So you get 5 - 1 which is 4.
The + operator has two meanings: Mathematical addition, and string concatenation. If either operand is a string, you get concatenation, not addition. More formally: It first converts its operands to primitives via the spec's abstract ToPrimitive operation, and then determines whether either operand's primitive value is a string, and does concatenation if so. In the case of +, it doesn't matter which operand (the left or right) is a string, it can be either and that makes it concatenation rather than addition.
So my question is how does JavaScript decides which operand type needs to be changed, does it happens internally (without in the knowledge of user) or is there any precedence of data type is there??
It's spelled out in very, very thorough detail in the specification, so if you have any doubts in a particular situation, that's where to look.
According to this precedence table incrementing has a high priority than comparison operators. And yet, when I increment and compare in the same expression, the comparison is evaluated first. Why is this?
var i = 0, k = 0;
console.log(i === k);
>true
console.log(i++ === k);
>true
>false
How come comparison operators are evaluated before postfix increment operator?
the postfix increment is indeed evaluated first, before the comparison, and so the preference table is correct. But the value of the postfix increment evaluation is not the incremented value, it's the value before incrementing. This is, as Adam pointed out, the intended behaviour of postfix increment.
That's how the post-increment operator works. It uses the variable in the expression, and then increments. If you want the increment to happen first, you would use the pre-increment operator like this:
console.log(++i === k);
You are confusing precedence with functionality. Postfix increment operator does have higher precedence than prefix increment operator and as such it is processed first. It is the functionality of prefix increment operator that determine that it should increment after returning. It is not a matter of of precedence.
Why does x = "1"- -"1" work and set the value of x to 2?
Why doesn't x = "1"--"1" works?
This expression...
"1"- -"1"
... is processed as ...
"1"- (-"1")
... that is, substract result of unary minus operation applied to "1" from "1". Now, both unary and binary minus operations make sense to be applied for Numbers only - so JS converts its operands to Numbers first. So that'll essentially becomes:
Number("1") - (-(Number("1"))
... that'll eventually becomes evaluated to 2, as Number("1"), as you probably expect, evaluates to 1.
When trying to understand "1"--"1" expression, JS parser attempts to consume as many characters as possible. That's why this expression "1"-- is processed first.
But it makes no sense, as auto-increment/decrement operations are not defined for literals. Both ++ and -- (both in postfix and prefix forms) should change the value of some assignable ('left-value') expression - variable name, object property etc.
In this case, however, there's nothing to change: "1" literal is always "1". )
Actually, I got a bit different errors (for x = "1"--"1") both in Firefox:
SyntaxError: invalid decrement operand
... and Chrome Canary:
ReferenceError: Invalid left-hand side expression in postfix operation
And I think these messages actually show the reason of that error quite clearly. )
Because -- is an operator in JavaScript.
When you separate the - characters in the first expression, it's unambiguous what you mean. When you put them together, JavaScript interprets them as one operator, and the following "1" as an unexpected string. (Or maybe it's the preceding "1"? I'm honestly not sure.)
"-1" = -1 (unary minus converts it to int)
So. "1" - (-1)
now, "+" is thje concatenation operator. not -. so JS returns the result 2 (instead of string concat).
also, "1"--"1" => here "--" is the decrement operator, for which the syntax is wrong as strings will not get converted automatically in this case.
because -- is an operator for decrement and cannot be applied on constant values.
If you evaluate 1|0,2|0 in JavaScript, you'll get 2.
If you evaluate 1|0+','+2|0, you'll get 1.
I cannot make sense of this.
The binary bitwise operators (including |) bind less tightly than the addition operator +. Thus
1|0+','+2|0
is really
1|(0+','+2)|0
which is
1|('0,2')|0
which is
1|0|0
which is 1. (The string "0,2" is converted to an integer; as a number it's NaN, but because NaN is a floating-point concept it turns into 0 when forced to be an integer.)
edit — as to the first expression, 1|0,2|0, that involves the JavaScript comma operator. The comma operator allows a list of separate, essentially independent (other than through side-effects) expressions to be "glued together" into something the parser will recognize as a single expression. When evaluated, each expression will be computed as it normally would be, but the value of the overall expression is just the value of the last one in the list. Thus, 1|0,2|0 will first cause 1|0 to be evaluated, but that result is thrown away and the overall value is just that of 2|0.
The comma operator is common to many languages that derive their expression syntax from C. (For all I know, C got it from somewhere else; it's hardly a revolutionary concept.) Because such languages allow for an expression — just one expression — to appear in several interesting grammatical situations, and because expressions can (and often do) have side effects, it's sometimes handy to be able to jam several separate expressions into a spot where the language really wants only one. That said, there are often cleaner and better ways to do things. In JavaScript, I would personally prefer to use an immediately-invoked function. It's more typing and probably a little worse for performance reasons, but I think it's a lot cleaner because it allows for an isolated namespace for temporary variables and more involved logic.
You need to look at an operator precedence table to make sense of this.
The expression 1|0,2|0 has bitwise-or at a higher precedence than the comma operator, so it's equivalent to (1|0), (2|0). The comma operator evaluates both operands and returns the second one, so you get the value of (2|0). That value is 2.
The expression 1|0+','+2|0 has addition at a higher precedence than bitwise-or, so it's equivalent to 1|(0+','+2)|0. The result of 0+','+2 is "0,2", which is not numerical, so it evaluates to NaN in numerical operations. It is coerced to 0 in bitwise-or, so that leaves 1|0|0, and the result of that is 1.
From MDN:
The comma operator evaluates both of its operands (from left to right)
and returns the value of the second operand.
Thus, in 1|0,2|0, first the two expressions 1|0 and 2|0 are evaluated from left to right and then the result of the last expression (2|0) is returned. 1|0 === 1 and 2|0 === 2, so the result of the last expression is 2 and that's returned.
In 1|0+','+2|0, the comma appears in a string literal which is concatenated with 0 and 2. The whole thing is evaluated as followed:
( 1 | ( (0+',')+2 ) ) | 0
( 1 | ( '0,'+2 ) ) ) | 0 (number + string = string concatenation)
( 1 | '0,2' ) | 0 (string + number = string concatenation)
( 1 | NaN ) | 0 (bitwise OR needs number operands. 0,2 fails to be converted, giving NaN instead)
1 | 0 (bitwise OR only deals with integers, so the floating-point NaN is cast to 0)
1