Ternary operator doesn't handle post-increments as expected - javascript

So this may be a silly question, but I've been running into this syntax mistake every now and again and can't seem to learn my lesson - because I simply don't understand why this doesn't work.
For some reason the ternary operator won't handle increments or decrements.
In the console, I found these results:
// Firstly
var iteration = undefined;
// Expected increment, unexpected result
iteration = iteration == undefined ? 0 : iteration++; //returns 0 every time
// Then I thought maybe ternary doesn't return assignments
iteration = iteration == undefined ? 0 : iteration+=1; //increments iteration
// Works as expected
iteration = iteration == undefined ? 0 : iteration+1; //increments iteration
While searching for answers I found another user had the same experience with the unexpected behavior.
After more searching I found that the pre-increment works fine:
iteration = iteration == undefined ? 0 : ++iteration; //increments iteration
And came across this answer when trying to determine why the pre-increment works.
It does make sense to me why it works and post-increment doesn't - kinda. I suppose at some point the incremented value could be overwritten by the initial value if the ternary order of operations works that way, but that's all I can think of.
But really the expected behavior that I would have from the post-increment would be for iteration to be returned, and then for it to be iterated...after.
For example, this bit of code:
var bar = undefined;
//foo is set immediately and bar is incremented after it is returned
foo = bar == undefined ? bar=0 : bar++; //sets foo to be what bar was before the increment
Hopefully you have been able to bear with me here. I do understand that at this point after finding many reliable and straight forward ways to get the job done that I don't need an answer, but I'm just stumped why it works this way.
Question:
Why does the ternary operator not update the post-increment (or postfix) value returned - after it has been returned?
A comment on this answer states that
counter++ evaluates to the current value of counter, then increments it. You would be assigning the old value of counter back to counter after you've incremented.
but I still don't why the order of operations behaves this way.
Another helpful Pre-increment vs Post-increment for C++ (ironically hilarious answer)

Whether the interpreter runs across an expression invoking pre- or post-increment, the variable is reassigned immediately, before the expression is resolved. For example:
iteration = iteration == undefined ? 0 : iteration++;
is like
function doPostIncrement() {
const preIncrementValue = increment;
increment = increment + 1;
return preIncrementValue;
}
iteration = iteration == undefined ? 0 : doPostIncrement();
Also, assignments resolve to values, so
iteration = iteration == undefined ? 0 : iteration+=1; //increments iteration
is like
function addOneToIncrementAndReturnIncrement() {
increment = increment + 1;
return increment;
}
iteration = iteration == undefined ? 0 : addOneToIncrementAndReturnIncrement();
It's not actually a function call, but it's not that dissimilar, in that the reassignment is done before the function resolves, or before the pre / post-increment expression resolves.

In an assignment expression, the entire right hand side gets evaluated first, and its resulting value is assigned to the left hand side. That means the post increment expression needs to be evaluated and turned into a value first, which will be assigned to the left hand side afterwards. The post increment operator doesn't know what larger expression it's a part of. It will be evaluated atomically. I.e., it won't first return its value, then complete the assignment operation, and then complete the post increment operation. When evaluating the expression iteration++, the value of iteration will be incremented and the expression results in the original value of iteration, all at once.

Related

Updating JavaScript Map value object property with spread and increment operators [duplicate]

My interest is in the difference between for and while loops. I know that the post-increment value is used and then incremented and the operation returns a constant pre-increment.
while (true) {
//...
i++;
int j = i;
}
Here, will j contain the old i or the post-incremented i at the end of the loop?
Since the statement i++ ends at the ; in your example, it makes no difference whether you use pre- or post-increment.
The difference arises when you utilize the result:
int j = i++; // i will contain i_old + 1, j will contain the i_old.
Vs:
int j = ++i; // i and j will both contain i_old + 1.
Depends on how you use them.
i++ makes a copy, increases i, and returns the copy (old value).
++i increases i, and returns i.
In your example it is all about speed. ++i will be the faster than i++ since it doesn't make a copy.
However a compiler will probably optimize it away since you are not storing the returned value from the increment operator in your example, but this is only possible for fundamental types like a int.
Basic answer for understanding.
The incrementation operator works like this:
// ++i
function pre_increment(i) {
i += 1;
return i;
}
// i++
function post_increment(i) {
copy = i;
i += 1;
return copy;
}
A good compiler will automatically replace i++ with ++i when it detect that the returned value will not be used.
In pre-increment the initial value is first incremented and then used inside the expression.
a = ++i;
In this example suppose the value of variable i is 5. Then value of variable a will be 6 because the value of i gets modified before using it in a expression.
In post-increment value is first used in a expression and then incremented.
a = i++;
In this example suppose the value of variable i is 5. Then value of variable a will be 5 because value of i gets incremented only after assigning the value 5 to a .
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argp)
{
int x = 5;
printf("x=%d\n", ++x);
printf("x=%d\n", x++);
printf("x=%d\n", x);
return EXIT_SUCCESS;
}
Program Output:
x=6
x=6
x=7
In the first printf statement x is incremented before being passed to printf so the value 6 is output, in the second x is passed to printf (so 6 is output) and then incremented and the 3rd printf statement just shows that post increment following the previous statement by outputting x again which now has the value 7.
i++ uses i's value then increments it but ++i increments i's value before using it.
The difference between post- and pre-increment is really, in many cases subtle. post incremenet, aka num++, first creates a copy of num, returns it, and after that, increments it. Pre-increment, on the other hand, aka ++num, first evaluates, then returns the value. Most modern compilers, when seeing this in a loop, will generally optimize, mostly when post increment is used, and the returned initial value is not used. The most major difference between the 2 increments, where it is really common to make subtle bugs, is when declaring variables, with incremented values: Example below:
int num = 5;
int num2 = ++num; //Here, first num is incremented,
//then made 6, and that value is stored in num2;
Another example:
int num = 5;
int num2 = num++; //Here, num is first returned, (unfortunately?), and then
//incremented. This is useful for some cases.
The last thing here I want to say is BE CAREFUL WITH INCREMENTS. When declaring variables, make sure you use the right increment, or just write the whole thing out (num2 = num + 1, which doesn't always work, and is the equivalent of pre-increment). A lot of trouble will be saved, if you use the right increment.
it does not matter if you use pre or post increment in an independent statement, except for the pre-increment the effect is immediate
//an example will make it more clear:
int n=1;
printf("%d",n);
printf("%d",++n);// try changing it to n++(you'll get to know what's going on)
n++;
printf("%d",n);
output:
123

What happens when an array object is incremented in JavaScript?

A very simple question, but I could not find the answer anywhere. Check the following code.
var myArray = [0,1,2,3,4,5,6,7,8,9];
for(i=0; i < myArray.length; myArray++){
console.log("Loop iteration step : "+i);
}
console.log("After array increment : " + myArray);
The myArray++ is not a typo. As you can see, the code will only run once. And after running it once, the loop terminates and myArray becomes NaN.
What is happening here to the array? How can an array become a NaN?
P.S: OK, more information since everyone is curious why myArray++ is not a typo. Yes, it was a typo at first. That's how I came up with this But that's not the problem I have here. I added the complete loop because I wanted to show the place I came up with this error.
EDIT: I have fixed some (shameful) misconception in terms of what the increment operand does. I fell into the same mistake of not looking up the actual docs. I hope this helps other users not fall upon the same mistake. (thank you for pointing that out #gurvinder372.)
I highly recommend you look up the documentation for "Increment" , the first sentence explains what's happening:
The increment operator increments (adds one to) its operand and returns a value.
One would think the Increment operator ++behaves as following:
myArray++ ---> myArray = myArray + 1;
When JavaScript evaluates myArray + 1 anything can come off that. In this case just try it out:
var myArray = [0,1,2,3,4,5,6,7,8,9];
myArray + 1
"0,1,2,3,4,5,6,7,8,91"
You could assume then it assigns a string back to myArray , when increment operator in the for loop evaluates, it determines that value is not a number, hence the NaN, and for loop exits before second iteration when condition i<NaNevaluates to false. Try it out:
var a = "a";
a++;
NaN
But that's not entirely correct (I messed up in terms of what myArray++ actually does under the hood, and it's better to understand what it's actually happening). Looking at the actual specs for Postfix Increment operator, we get the following:
Steps
myArray++
lhs = myArray
oldValue = Number(myArray)
oldValue = NaN
newValue = oldValue + 1
newValue = NaN + 1
newValue = NaN
myArray = NaN
The Postfix Increment operator returns oldValue, NaN and now myArray=NaN
So what you end up with in your for loop after the first iteration when the Postfix Increment operator runs is:
for ([initialization]; [condition]; [final-expression])
statement
for ([initialization]; i<myArray.length; NaN)
statement
for ([initialization]; i<NaN.length; NaN)
statement
for ([initialization]; i<undefined; NaN)
statement
for ([initialization]; false; NaN)
statement
I hope this helps clear up a bit what's happening in every step and part of the loop and why myArray ends up with value NaN.
Here's something interesting to try and see if you understand why in this infinite loop your myArraygets to stay as [...] but counter is NaN after second call.
var myArray = [1,2,3,4,5,6,7,8,9];
var counter = myArray;
for(let i=0; i<myArray.length; counter++){
console.log("Infinite calls. Never leaving and counter is " + counter);
// i++; if you don't want to eat up that infinite loop.
}
Answer
You get the infinite loops because your expression i<myArray.length will always evaluate to True since i is never modified. Meanwhile, counter will go to NaNafter first iteration because of what was explained at the start of the post. myArray stays cool because the Postfix Increment is done upon counter.
Why does this loop iterate but the one you did, does not? Because in the one you did you end up changing the value of myArrayinto NaNforcing the expression in the loop i<NaN.length---> i<undefined to be false after first iteration, causing the loop to exit.
As per spec for Postfix Increment Operator
Let oldValue be ToNumber(GetValue(lhs)).
And
var myArray = [0,1,2,3,4,5,6,7,8,9];
Number(myArray) //NaN
Hence myArray++ => NaN
Demo
var myArray = [0,1,2,3,4,5,6,7,8,9];
console.log( "Just increment using postfix operator ", myArray++ );
myArray = [0,1,2,3,4,5,6,7,8,9];
console.log( "Number conversion ", Number(myArray) );
When you do ++ and if the variable is not of type number, it will be converted to string using toString and then converted to number.
Object.toString returns [object Object], so Number('[object Object]') returns NaN
Also when you do ++ is a short hand for += so myArray++ is equal to myArray = myArray + 1;. Now that your myArray is not an array, it does not have property length and it returns undefined (as everything in JS is an object) and the loop breaks.
As rightly pointed out by #barmar, Array.toString returns array.join. So it is equal to Number("0,1,2..."). Since comma(,) is not a valid numeric character, it returns NaN. Also, when value is compared to NaN, it returns false hence breaking the loop.
Sample:
var myArray = [0,1,2,3,4,5,6,7,8,9];
console.log(myArray.toString())
console.log(Number(myArray.toString()))
console.log(1<NaN)

JavaScript Loop returns unexpected result

Can anyone tell me why this logs 11, instead of 9?
function foo() {
function bar(a) {
i =3;
console.log( a + i );
}
for (var i=0; i<10; i++) {
bar( i *2 );
//I know, infinite loop
}
}
foo();
If i is hard-coded in bar(){}, shouldn't the logged result be 9?
This is part of a Scope class and I am lost.
Thanks.
In the first iteration, i is 0 which is smaller than 10. 0 (2 * i) is passed as a to bar. i gets set to 3, then the sum is 3.
In the next iteration, i is incremented to 4 (which is still smaller than 10), then 8 (2 * i) is passed as a to bar. i gets reset to 3, then the sum is 11.
The next iteration is the same, i is incremented from 3 to 4 again and so on.
Your misunderstanding seems to be that the value of a doesn't change because i gets changed, the multiplication is evaluated first. Or you just missed the i++ statement in the loop header.
#Bergi has the right answer, I just want to expand on it a bit. For primitive types like a string or number the parameter is passed by value. Here you are passing i into bar as the value a. Any changes to i or a will not effect the other's value. This also will not give you an infinite loop as the values for i in this case are [0, 4,5,6,7,8,9]
Now if i had been wrapped inside of an object that was passed to foo then you would have the problem you are asking about. Objects passed to javascript functions are passed by reference, so changes to the object in bar also happen in foo.

how does this if statement works and means? (Javascript)

This function counts number of all characters of a string into a string. I am not fully understanding the if statement here and how it works.
function getFrequency(string) {
var freq = {};
for (var i=0; i<string.length;i++) {
var character = string[i];
if (freq[character]) {
freq[character]++;
} else {
freq[character] = 1;
}
}
return freq;
};
I thought freq[character] is the property of the object such as A B how does it work with if(freq[character]) also how does the increment of freq[character]++ works?
I have made test like this to try and understand it.
var v = {};
v.h = 3;
v["h"]++;
v["h"] = v["h"] + 1;
v.h++;
v.h = v.h + 2;
console.log(v);
console.log(v["h"]);
I think I can guess the if statement works that if the property exists but I thought JS has an object property calls .hasOwnProperty shouldn't this be used instead?
As for the increments, to my test, it works but I just don't get the reason.
Can someone give me a hand to elaborate this?
Thanks in advance
In javascript, objects are associative arrays. And vice versa. There is no difference between the two concepts.
So defining this variable as an empty object:
var freq = {};
... is actually creating an associative array (like a dictionary or map) with no keys added yet.
Moving on, let's take an input string like eek. The code here will look at the first letter and treat freq[character] the same as freq['e'], which is the same as freq.e.
In this code, the initial value of any letter in the freq object is undefined. So that initial if() check for the first "e" in our string actually looks like this:
if(undefined)
Javascript has the concept of "truthy" and "falsy" values; anything in javascript can be evaluated as a boolean, and (in most cases) a sensible result is achieved. Looking at undefined, Javascript will simply treat this a falsy value, fall to the else block, and therefore execute this code:
freq[character] = 1;
As already established, this is the same thing as freq.e = 1;
Now when the loop continues to the next letter (also an "e"), javascript will end up evaluating the expression if (1). Javascript treats this and all other non-zero numbers as "truthy", so this time will execute the following line:
freq[character]++;
Again, that's the same as freq.e++, where freq.e had a value of "1" that can now be incremented to "2".
One more time through the loop for the final letter "k". This time we get freq.k, which is still undefined. Undefined is falsy, so control falls to the else block, and freq.k is set to "1".
Now you can see how we can start to increment letters in the array as you find them in the string, even though it appears that you never defined an array in the first place, never set any values to anything other than "undefined", and never had a real boolean value to check against.
if (freq[character]) checks if the value is "truthy". That is, it's not false, null, undefined or 0. The first time we encounter any character the value will be undefined, since the object literal is created empty, so the "truthy" check will fail and control will fall to the else block.
So when we first see a specific letter set the value to 1 (which is now "truthy").
Any subsequent encounters of that letter just increment the value, which would be equivalent to say freq[character] = freq[character] + 1;. The increment syntax is just a shorthand.
if (freq[character]) checks if the object freq has a property on it with the value of character as the name. The result of this expression evaluates to true or false.
It can be more explicitly stated, as the following non-exhaustively illustrates:
if (freq[character] == null)
or
if (typeof freq[character] === 'undefined')
The danger in not being explicit when evaluating if an object is undefined or null, is if it is actually set to a different type that evaluates to true or false (0, 1, '0', true, false).

Variable initialization using increments

is it possible to initialize a variable by incrementing it? Here's an example of what i mean:
In this example, x has not been initialized yet
>x += 1
>print(x)
1
No, that code is not guaranteed to work in all ECMAScript (JavaScript) interpreters.
Most engines should throw a ReferenceError, saying "x is not defined". Even a permissive interpreter that might declare x automatically for you would define it as "undefined" and undefined + 1 is NaN, not 1.
No. That's not possible in JavaScript. Variables must be declared before they can be used / incremented.
var x = ++x || 1;
On the initial run, x is undefined, first part of the OR will be false, though the second one will be used.
On any consecutive run the first part of OR will be used, while the second one will be ignored.

Categories

Resources