What happens when an array object is incremented in JavaScript? - 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)

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

Ternary operator doesn't handle post-increments as expected

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.

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).

listToArray Eloquent JavaScript

The book says:
To run over a list (in listToArray and nth), a for loop specification like this can be used:
for (var node = list; node; node = node.rest) {}
Every iteration of the loop, node points to the current sublist, and the body can read its value property to get the current element. At the end of an iteration, node moves to the next sublist. When that is null, we have reached the end of the list and the loop is finished.
Question 1: Could you explain how the condition of the for loop works? I understand that it is checking whether the node(the current list) is null.. but how does the "node" argument by itself work?
Question 2: why doesnt the following code work?
function listToArray(list){
var result = [];
while(list.value != null){
result.push(list.value);
list = list.rest;
}
return result;
};
console.log(listToArray(list));
To understand how this works, you need to know two things:
How java script For loop works.
What are truthy values.
The syntax for the for loop statement:
for ([initialization]; [condition]; [final-expression]) statement
[condition] An expression to be evaluated before each loop iteration.
If this expression evaluates to true, statement is executed. If the
expression evaluates to false, execution skips to the first expression
following the for construct.
In Java script, a truthy value evaluates to true when evaluated in a Boolean context.
All values are truthy unless they are defined as falsy (i.e., except
for false, 0, "", null, undefined, and NaN).
So till node is null at one point, we may say that node is truthy and evaluates to true.
When the statement, node = node.rest assigns a null value to node, there the for loop exits.
The below code does not work because, list.value may be undefined, or as a fact any other falsy value other than null.
function listToArray(list){
var result = [];
while(list.value != null){
result.push(list.value);
list = list.rest;
}
return result;
};
console.log(listToArray(list));
instead try, while(list.value).
...but how does the "node" argument by itself work?
node is a variable. A variable is resolved to its value. E.g. if I have
var foo = 3;
alert(foo + 1);
it will resolve foo to the value 3 and then add 1 to it. Similarly in this case, node is resolved to whatever value it has, that value is converted to a Boolean value (i.e. Boolean(node)) and then tested whether it is true or false.
If the value of node is null, then Boolean(node) will return false.
why doesnt the following code work?
Can't really tell without knowing what list is and what exactly "does not work".
But presumably, list.rest is null at some point, in which case you would try to access null.value which throws an error. The equivalent version to the for loop would be to compare list itself:
while (list != null)
A simpler way is to use:
var result = Array.prototype.slice.call(list);
this will turn the list into an array
function listToArray(listValue){
var arrayResult = [];
while(listValue.list){
arrayResult.push(listValue.value);
listValue = listValue.list;
}
arrayResult.push(listValue.value);
return arrayResult;
}

How does parentheses work in arrays? (javascript) [duplicate]

This question already has answers here:
What does the comma operator do in JavaScript?
(5 answers)
Closed 8 years ago.
I don't get why this.array[0] equals 1 if this.array[0] = [(2,1)]?
What does Javascript do with the 2 and how do i reach/use it? How does parenthesis work inside arrays?
I'd like to do different things with X if the boolean before it is true or false.
this.array[0] = [(true, X)] and this.array[0] = [(false, X)].
Parenthesis in that context act as a statement with the last item passed being the passed value.
In other words:
(2, 1) === 1
The 2 is evaluated, however, so:
(foo(), bar())
is effectively doing:
foo();
return bar();
What you want in this case is [2, 1]
If you use the comma operator inside parentheses, it evaluates both items and returns the second. This is rarely used, but there are two canonical reasons for using the comma operator:
Loop Logic
You can use the comma operator to have more complex login in a loop, like this:
for (var i = 0, j = 10; i < a && j > b; i++, j--) { }
Side Effect in Condition
You can use the comma operator to execute a statement before evaluating a condition, like this:
if (DoX(), CheckIfXHasBeenDoneSuccessfully()) { }
Other than that, the comma operator is basically naff. In your parentheses, (2,1), both 2 and 1 are evaluated and 2 is ignored and 1 is returned. You can use parentheses inside an array, but you will almost never want to put commas inside of the parentheses.
What I believe you want is something like this:
var bool = true; //or false, if you like
if(bool){ this.array[0] = X }
else { this.array[0] = Y }
its not the parens, its the incredibly arcane comma. What a comma will do is that it will evaluate each expression in turn, and return the result of the last one.
Your snippet is either a bug, or someone being an ass. Its the sort of thing that is only rarely useful, and probably shouldnt even be used in those times due to how confusing it is to people.
I think you want array[0] = [2,1].
In javascript, the expression
(2, 1)
evaluates to 1. The parentheses cause the expression 2, 1 to get evaluated before the brackets turn it into an array.
You actually want
this.array[0] = [false, X];

Categories

Resources