Javascript: Why doesn't (p+1)++ work? - javascript

Regarding
p = 0;
(p+1)++;
> ReferenceError: Invalid left-hand side expression in postfix operation
and
p = 0;
++(p+4);
> ReferenceError: Invalid left-hand side expression in prefix operation
I just got a bit of a surprise, as I expected postfix/prefix operators to be ok with working on the resolution of the expression (brackets have the highest operator precedence).
Could someone give me with a line or three to explain what is happening here?
Thanks
EDIT: Thanks for the quick responses, first answer marked as the answer. I feel I should also point people to the indepth answer from #thefourtheye below

++ increments the value of a variable, so it is larger than before. Eg:
var x = 3;
x++;
alert(x); // will show 4
For there to be any point for this, the expression to the left of ++ must be accessible and mutable, otherwise the increment would be possible. Eg:
3++
doesn't make any sense, as 3 is a constant and can't be incremented. We don't want this to be possible:
3++;
alert(3); // outputs 4???
This is why your expression doesn't work. Ie:
var p = 2;
(p + 1)++;
has the same problem as above. (p + 1) will evaluate to 3, and ++ can't change the value of the constant 3.

You are trying to increment (), the increment/decrement operator can be apply on variable, try the sample code
(p++) + 1
OR
(++p) + 1

Remember that when you write p++, that actually gets translated to p = p + 1. The operators ++ and -- are convenience notation for incrementing/decrementing a variable for future use. But how is (p+1)++ or ++(p+4) supposed to be translated? Those sort of imply that 1 or 4 are being incremented/decremented for future use, which doesn't make sense.

When you have an expression like this
(expr)++;
These are the operations JavaScript will do internally
Resolve the actual object referenced by expr.
This step is important, because you can even do something like this
var a = {b: 1};
++a.b;
a.b++;
console.log(a.b);
# 3
Now, JavaScript has to resolve the actual object to be incremented. In this case, it will be b in a.
Get the value at the reference and convert that value to a Number.
This step is also very important, because you may even have values like this
var a = {b: '1'};
console.log(++a.b);
# 2
JavaScript will try its best to get a number value, instead of failing immediately.
Increment the number.
Store the new vale in expr. This is step where your expression is failing.
In your case expr is p + 1, when it is resolved the value would be just a numeral, whose value can never be changed. (You can never change the value of 1 to something else). So, after the incrementing part, when the new value has to be stored back, JavaScript doesn't find a valid reference to store it. That is why it throws this error.
ReferenceError: Invalid left-hand side expression in postfix operation
This error message is actually thrown from internal PutValue method. The very first step goes like this
If Type(V) is not Reference, throw a ReferenceError exception.
Reference: ECMA Script 5.1 Standard Specification for Prefix Increment Operator

Related

Why can't we increment (++) or decrement (--) number literals

For example, in the following JavaScript code, why do we not get errors when using variables, but when a number literal is used, I get an error (running on node v6.9.5)?
let x = 2;
console.log(x++); //2
let y = 2;
console.log(++y); //3
console.log(2++); //ReferenceError: Invalid left-hand side expression in postfix operation
console.log(++2); //ReferenceError: Invalid left-hand side expression in prefix operation
My understanding is that this doesn’t work because you can’t mutate the literal 2. In the previous example, you returned x or y (either before or after incrementing), so it was now equal to +1 its previous value (so x/ y now pointed to 3, rather than 2). However, you can’t increment 2 to be +1 its previous value and then have it point to the literal 3. 2 will always be 2, 2 will never point to 3.
Am I correct in my reasoning?
Literals are constants, and increment/decrement would try to change its argument respectively. But constant values cannot be changed.
It would be the same like coding something like
2 = 2 + 1;
The argument of a increment/decrement operator must be a lvalue -- essentially, it has to be an expression that you could assign a value to. This can be either a variable, or certain types of simple structured expressions (like array[0]++ or object.foo++).
Constants aren't lvalues. You can't assign a value to them (3 = abc), nor can you mutate their values with the increment or decrement operators.

why ++ or -- can't be applied directly on literals in JavaScript?

I am learning JavaScript, now in the operators chapter. I was wondering why ++true is an invalid expression in JavaScript and +true is just fine. I guess the differences are because of the way ++ (or --) operator work in JavaScript. Just curious to know what happens when ++ is applied.
console.log(+true); // 1, fine
console.log(++true); // SyntaxError
Why true isn't implicitly converted to number and incremented as it is in the case of +.
When the value is stored in a variable, ++ does the expected job, but we can't use it directly on literals.
++ adds 1 to the value in the variable, and also assigns that incremented value back to the variable. This doesn't make sense when the parameter isn't a variable. You can't change the value of true. ++true is equivalent to true = true + 1.
You can't use ++ on any literal, e.g. console.log(++3) is also an error, since it's equivalent to console.log(3 = 3 + 1).
Note that ++ will convert a boolean to an integer if necessary, but it has to be in a variable:
x = true;
console.log(++x);
Because when you use ++ or --, it changes the value of the variable you're operating on.
var a = 1;
console.log(++a);
console.log(a);
console.log(--a);
console.log(a);
By doing ++true you're implying that you're changing the value of true which would be an absolutely terrible thing to do.
Since true is a non-mutable value, you can't use a mutating operator on it.
The ++ and -- pre- and post-decrement operators implicitly modify the operand variable or property. The operand must be something that can appear on the left side of an assignment operator, or else it doesn't make sense to use ++ or --.
The same is true for C, C++, Java, and I imagine most if not all the C-heritage programming languages that include those operators.
The ++ and -- operator changes the value.
In your case you're trying to increment value of boolean or non mutable value which is not possible the way you're doing.
var x = 10;
console.log(++x) // Output 11
console.log(x++) // Output 12
//Or
var y = true;
console.log(y++) //Output 2
In second scenario output is two because true is equal to 1 and false is equal to 0.

JSHint -Expected a conditional expression and instead saw an assignment

I am well aware of similar questions, but I still can't solve mine basing on those.
So, my code looks like this:
for (var e, i = 0; e = formErrors[i]; i += 1)
JSHint returns said error in char 39, so with ; after formErrors[i]. What can I do?
JSHint is warning you of a potential bug. It is expected that the 2nd part of a for statement will be a Boolean expression. Normally, you'd use one of the comparison operators for this (==, ===, !=, > etc..). Since the expression is e = formErrors[i] it looks like it might be a mistake, possibly due to a missing equal sign. This is a common typo that causes a lot of bugs.
Apparently, in this case it is not a bug, but rather an intentional usage of the fact that any expression evaluates to something, and an assignment expression evaluates to the assigned value:
var x;
alert(x = 1);
So the for statement actually assigns a new value to e, but also evaluates that value as a condition, casting it to Boolean if required.
You could refactor your code such that it both assigns the value and uses a casting operation that would satisfy JSHint and make the code a bit more obvious to the reader:
for (var e, i = 0; !!(e = formErrors[i]); i += 1)
The 2nd ! (the one directly in front of (e...) causes a casting to Boolean, but also negates it, the 1st ! reverts this negation.
That's just a very weird way of writing a loop. JsHint expects a boolean expression ("conditional") there, and judges that your assignment is a mistake and you actually wanted a comparison (== instead of =).
What you should do is switch to the following common array iteration idiom:
for (var i = 0; i < formErrors.length; i += 1) {
var e = formErrors[i];
…
(Which works the same as your original code for non-sparse formErrors arrays that contain no falsy values.)
Or alternatively, if you want to write non-idiomatic code, dump jshint :-)
e = formErrors[i] is an assignment, don't you want a condition there? use a comma after i=0 in that case, else put a condition after the semicolon.
Typically, the middle element in a for loop is the condition that is used to decide whether to continue the loop or not. You have an assignment there, if you wanted a condition you should use e === formErrors[i] (or with a double =, but that is usually not recommended).
An assignment can technically work, because e can be, for example, some object (true) or null (false). But that is considered bad coding style, usually, and won't make for very readable code.

Operator assigning with a pre-increment

For looping variables (usually array indexes) I do a lot of pre-incrementing and modulus assigning in a loop. In other languages this would look like
++_index %= LENGTH;
(broken up version on multiple lines)
_index++;
_index = _index % LENGTH;
This of course increases the _index by 1 and then assigns the modulus back to itself.
but I have problems doing this in Javascript I get the horrible ReferenceError: Invalid left-hand side in assignment.
I suspect what it is actually doing is trying to do assign the modulus of a variable called "++_index" which of course, there is none as its invalid.
I tried using parentheses to hopefully have it read it has _index correctly but still this seemed to be a bust.
(++_index) %= LENGTH;
I have resorted to using the broken down version of
++_index;
_index %= LENGTH;
But I cannot find any documentation on the issue at hand. All my google-fu is bringing back people using = within if statements.
Could someone with far superior google-fu direct me to some documentation that can explain this in more depth. As I said, I suspect its trying to do the assignment to ++_index, rather than evaluate it, increment it and pass reference to variable for the next stage of assigning the modulus. But something (or someone) to confirm or deny this would be most beneficial.
The JavaScript prefix increment operator doesn't return a reference, it just returns a value. It's invalid to assign to a number, so that's why it throws a ReferenceError.
You either have to do this:
_index = ++_index % LENGTH;
or this:
++_index;
_index %= LENGTH;
Specification:
Let expr be the result of evaluating UnaryExpression.
Let oldValue be ToNumber(GetValue(expr)).
ReturnIfAbrupt(oldValue).
Let newValue be the result of adding the value 1 to oldValue, using the same rules as for the + operator (see 12.7.5).
Let status be PutValue(expr, newValue).
ReturnIfAbrupt(status).
Return newValue.

Why does +++x gives an error message when +x++ works fine?

var x = null;
+++x generates a ReferenceError, but when I do the same using postfix increment operator +x++, it works just fine.
The LeftHandSideExpression for the ++ operator must not be a number. For instance
1++;
will fail with the same error (invalid increment operand). You can only apply the pre- and postincrement operators on variables/identifiers/expressions.
Since the + sign casts the null value into a number (0), you got the same outcome.
Examples:
var foo = null,
bar = 5;
foo++; // 0
0++; // invalid increment operand
null++; // invalid increment operand
(+bar)++ // invalid increment operand
foo++ +2; // 2
+x++ is split into two steps:
+x initialises x to 0, so it's no longer null.
x++ then increments x, which works since x is no longer null.
+++x is also split into two steps, but in a particular order:
++x is evaluated first, which throws the exception because x is null.
+x would then be evaluated, except you've already had an exception.
I think your assumption was that +++x would be parsed as ++(+x), but it's actually parsed as +(++x). It's an ambiguous-looking syntax, the language designers had to pick one of the two ways to parse it, and from your point of view they chose "the other one".
To be honest, there's absolutely no value in formatting your code this way anyway - all you end up with is dubious-looking code which is destined to confuse people.
if u used the x= 0 ;
x will be initalized with a integer type that will accept the ++x operator while ++(+x)
is like a ++(+null)
so better try to change to X = 0 ;

Categories