Why is `x === x++` true and `x++ === x` false in Javascript? - javascript

Can you explain the difference between these two logical operations :
let x = 1;
console.log('x = ' + x);
console.log('x === x++ : ' + (x === x++));
x = 1;
console.log('x = ' + x);
console.log('x++ === x : ' + (x++ === x));

The postfix increment (y = x++), does increase the value, but evaluates to it's previous value. It barely equals:
x² = x; // evaluate previous value of x
x += 1; // increase x
y = x²; // use previous value
So therefore x === x++ is equal to:
// evaluate left side of ===
x¹ = x;
// evaluate right side
x² = x;
// ++
x += 1;
// comparison
x¹ === x² // true
wereas x++ === x is:
// evaluate left side
x¹ = x;
// ++
x += 1;
// evaluate right side
x² = x; // x was already incremented!
// comparison
x¹ === x²

x === x++ : first compare x with x then x++
x++ === x : first x++ and then compare the result of x++ with x

When evaluting the === operator in javascript, it evalate the left operand first, and then the right operand, and does the comparison in the last. See ecma262.
And, when x++ is evaluted, the value of x is changed, and the result of x++ is the original (unchanged) value of x.
So, in x === x++ ,both x and x++ evalutes to the original value of x,the value of x is changed after that. So the result is true.
In x++ === x, the value of x is changed when evaluating the left x++, and the left operand evaluates to the original value. But the right operand eveluates after this, so it evaluates to the changed value of x. So the result is false.

x++ is a post increment operator, it basically put the value of x already and then increment it by 1.
In the first case x===x++. It suggests, 1===1 while in the second case x++===x ,the value of x is incremented before the comparison, So it becomes 1===2,which is false of course.

This happens because the order of increment operator (before or after the variable) matters.
Using x++ will return the variable first then increment it, while using ++x will increment it first then return the result.
Example:
x = 0;
console.log(x++, x); // 0, 1 (first return the variable then increment)
console.log(++x, x); // 2, 2 (first increment then return the variable)
In the first comparison, you are incrementing it after all uses of variable:
x = 0;
// 0 === 0
x === x++
In the second comparison, you first use the x value, then increment it and compare with new x value:
x = 0;
// 0 === 1
x++ === x

Interesting.
In the second case, x++ is being evaluated as 1 then it increments x (becomes 2). So the comparison ends up being 1 === 2

This is basic computer science, x++ means use then update.
x = 1;
x === x++
here value of x is changed after comparison is over.
x++ === x
here in beginning, x++ value remains 1 but once === is executed, value of x changes to 2.

It's because the value x is incremented just before you read it again so x++ === x is false and x === x++ is true.
There is some other operator that looks almost the same ++x which increments variable immediately.
let x = 0;
console.log(x++); //0
console.log(x); //1
let y = 0;
console.log(++y); //1
console.log(y); //1

The operators ++ can be placed either after a variable.
When the operator goes after the variable, it is in “postfix form”: x++.
The “prefix form” is when the operator goes before the variable: ++x.
let x = 1;
console.log('x = ' + x);
//print x = 1
console.log('x === x++ : ' + (x === x++));
//(x === x++) that means
//(1 === 1)
//true
x = 1;
console.log('x = ' + x);
//print x = 1
console.log('x++ === x : ' + (x++ === x));
//(x++ === x) that means
//(1 === 2) works the same as x = x + 1, but is shorter
// false

First, I assume that the expression is evaluated from left to right, see the demonstration below:
console.log('(1 == 2) == 2 - left first - ', (1 == 2) == 2 )
console.log('1 == (2 == 2) - right first - ', 1 == (2 == 2) )
console.log('1 == 2 == 2 - same as left first - ', 1 == 2 == 2 )
or in ECMA 262
Theory done, so in x === x++, under the hood it transplies to
// init temporary variables x_left/x_right in CPU for the calculation
x_left = x_right = x;
// `===` is evaluated first:
x_left === x_right; // true
// then `x++` evaluate, doesn't affect the result `true` above
x_right += 1;
x = x_right;
And in x++ === x, it transpiles to
// init temporary variables for the calculation (in CPU)
x_left = x_right = x;
// `x++`
x_left += 1;
x = x_left;
// `===` operator
x_left === x_right; // false

x === x++ Here, x=1 before comparing, so returns true.
x++ === x Here, because of operator precedence,
this equals x === ++x where x is incremented and hence returns false.

Related

(JavaScript) Why does a continue statement inside 'if' in a while loop crash the browser?

I want to write a program in JavaScript to print all the numbers from 1 to 20 except 5 and 10. When I use a for loop like this:
for (x = 1; x <= 20; x++) {
if (x == 5 || x == 10) {
continue;
}
document.write(x + ' ');
}
It works properly and prints 1 2 3 4 6 7 8 9 11 12 13 14 15 16 17 18 19 20.
However, when I try to use a while loop like this:
var x = 1;
while (x <= 20) {
if (x == 5 || x == 10) {
continue;
}
document.write(x + ' ');
x++;
}
It makes the webpage unresponsive and I get a prompt asking me to close it. What is the problem here?
The problem is the following, inside the for-loop the continue will jump back to the update expression x++ but in the while loop it will jump back to the running condition while(x <= 20)
Referencing the mdn docs.
In a while loop, it jumps back to the condition. In a for loop, it
jumps to the update expression.
Because you are not updating the counter inside your condition
while (x <= 20) {
if (x == 5 || x == 10) {
continue;
}
x will remain 5 and gets never updated because with the continue inside the while-loop it jumps back to the running condition. This will end up in an endless loop.
To solve it you can increment the counter before the continue statement inside the while-loop
while (x <= 20) {
if (x == 5 || x == 10) {
x++
continue;
// for (x = 1; x <= 20; x++) {
// if (x == 5 || x == 10) {
// continue;
// }
// document.write(x + ' ');
//}
var x = 1;
while (x <= 20) {
if (x == 5 || x == 10) {
x++
continue;
}
document.write(x + ' ');
x++;
}
In the first case the loop declaration for (x = 1; x <= 20; x++) handles incrementing x between iterations, so every time the loop body executes, you get a different value of x.
In the second case, x++ is only executed if x is neither 5 nor 10. So, when x reaches 5 it's the loop will keep executing with x = 5 forever, since nothing is changing it.

Function to create new array producing undefined

I am trying to write a program that creates an array and populates it with a range of numbers. The function range's x, y, z variables correlates to the start number, the end number, and the number value of each step. My goal is produce an array with all the numbers between (and including) x and y that is created with each step. Here is the code:
let newarray = []
function range (x, y, z){
if (x === undefined || y === undefined || z === undefined || (x > y) || (z < 0)) {
return newarray; // returns empty array if x, y, or z is undefined, x is greater than y or z is a negative integer
}
else if (y > x) {
for (x; x < y; x = x += z) {
newarray.push(x); //pushes x into an array then adds z into x and loops until x exceeds y
}
}
else {
return newarray; //prints out new array
}
}
console.log(range(0, 10, 2));
console.log(range(10, 30, 5));
console.log(range(-5, 2, 3));
right now it is producing undefined for all three numbers. My research suggests something about asynchronicity? I'm not sure what that means.
A few things are at play here:
newArray should be defined inside the function scope rather than as a global variable. Otherwise, subsequent calls to the function will keep appending onto the same array, which is likely not your intention (and if it was, there's array.concat() for that).
Your last else is unreachable, so the function will either return an empty array for input failing your validation or return undefined when control reaches the end of the function after populating the array in the else if block.
x = x += z is probably intended as x += z.
You should disallow z === 0 otherwise you'll wind up with an infinite loop.
Normal JS style is to camelCase variable names.
Additionally, I find it's easier to write positive conditionals than negative conditionals. In this case, enumerating what arguments are allowed seems cleanest. This approach enables you to only have one return statement and fewer conditional branches, mitigating potential confusion.
Here's a version that addresses these issues:
function range(x, y, z) {
const newArray = [];
if ([x, y, z].indexOf(undefined) < 0 && x < y && z > 0) {
for (; x < y; x += z) {
newArray.push(x);
}
}
return newArray;
}
console.log(range(0, 10, 2));
console.log(range(10, 30, 5));
console.log(range(-5, 2, 3));
Note that the section where you check else if (y > x) does not have a return. When this condition is true, your function returns undefined. To fix the problem, just add return newarray; as the last line in the function. Then remove all other lines with return new array;.
The else block is not required as it will be unreachable and will
return undefined.
Corrected x = x + z from x = x += z.
The array declaration was outside, so every time the old data will be
appended with newer data from the for loop.
function range (x, y, z){
let newarray = [];
if (x === undefined || y === undefined || z === undefined || (x > y) || (z < 0)){
return newarray;
}
else if (y > x) {
for (x; x < y; x = x + z){
newarray.push(x);
}
}
return newarray;
}
console.log(range(0, 10, 2));
console.log(range(10, 30, 5));
console.log(range(-5, 2, 3));

JavaScript operator precedence

According to Mozilla, the === operator has higher precedence than the || operator, which is what I would expect.
However, this statement evaluates to the number 1, rather than false.
let x = 1 || 0 === 0; // x === 1;
You have to wrap in parentheses to get a boolean:
let x = (1 || 0) === 0; // x === false;
What is the explanation?
Note: This is not a duplicate of this question, which does not have anything about equality operators - JavaScript OR (||) variable assignment explanation
Higher operator precedence is like a parenthesis around the operands.
let x = 1 || (0 === 0);
The second part gets never evaluated, because of the truthy value of 1
.
|| is a short circuit operator and conditions are evaluated from left to right.
So in left || right, if the left condition is true, the whole condition is evaluated to true and the right one is never evaluated.
In
let x = 1 || 0 === 0; // x === 1;
x = 1 assigns 1 to x and the second condition after || is never evaluated as if (1) is evaluated to true.
And in
let x = (1 || 0) === 0; // x === false;
(1 || 0) is evaluated to true as if (1) is still evaluated to true.
And then true === 0 is evaluated to false.
So x is valued to false.

If then logic with && ||

Can someone explain to me or point me to documentation as to why the following function doesn't work?
var x = 1;
var y = 2;
var z = 1;
function logicTest() {
if ((x && y && z) === 1) {
return true;
} else {
return false;
}
}
console.log(logicTest())
I know that I can type it out the long way as follows:
var x = 1;
var y = 2;
var z = 1;
function logicTest() {
if (x === 1 && y === 1 && z === 1) {
return true;
} else {
return false;
}
}
console.log(logicTest())
But I'm really trying to understand why the first doesn't work and also if there is a better way of typing the second if/then statement or if that is just the way it will always have to be.
Thanks!
The expression
((x && y && z) === 1)
first involves the evaluation of (x && y && z). To evaluate that, JavaScript tests, in sequence, the values of x, y, and z. If, left to right, one of those values when coerced to boolean is false, evaluation stops with that (uncoerced) value as the value of the whole thing. Otherwise, the value of that subexpression will be the value of z, because it's the last subexpression in the && sequence.
In this case, x, y, and z are all non-zero numbers, so the overall result will be 1, because z is 1.
What you seem to want to be able to do is test whether all of a set of subexpressions are equal to the same value. That, as you've found, can only be determined by explicit comparison. It's also something that could be done by creating a list and then using array functions to perform the tests, which would be useful when there are more than just three subexpressions to test.
Also, on a stylistic note:
function logicTest() {
if (x === 1 && y === 1 && z === 1) {
return true;
} else {
return false;
}
}
Performing tests with relational operators like === generates boolean values. It's more concise to take advantage of that:
function logicTest() {
return x === 1 && y === 1 && z === 1;
}

x >= x pattern in JavaScript

When reading source of D3.js I saw x >= x pattern. If it is for detecting NaNs among numbers, why not just isNaN(x) or x == x?
Source, where I encountered it:
d3.min = function(array, f) {
var i = -1, n = array.length, a, b;
if (arguments.length === 1) {
while (++i < n) if ((b = array[i]) != null && b >= b) {
a = b;
break;
}
while (++i < n) if ((b = array[i]) != null && a > b) a = b;
} else {
while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) {
a = b;
break;
}
while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b;
}
return a;
};
From my investigations, d3.min is supposed to work on any kind of orderable values, not only numbers. isNaN would only work numbers.
d3 was actually using == at some point. This commit introduced the x == x test:
Unlike Math.min and Math.max, it doesn't make sense to return negative or positive infinity for d3.min and d3.max; the D3 functions return the minimum value according to an arbitrary ordering, not by numeric value. Instead, the minimum or maximum of an empty array, or an array that contains only degenerate values, should always be undefined.
This commit changed x == x to x <= x (which was later again changed to x >= x):
In addition to NaN, which is not equal to itself, you can have objects that are not orderable due to defined valueOf functions which return NaN. For example:
var o = new Number(NaN);
Here, o == o is true, but o <= o is false. Therefore it was possible for d3.min, d3.max and d3.extent to observe these non-orderable values rather than ignore them as intended. The fix is to check !(o <= o) rather than o == o.
OK, I see that x >= x gives false for both NaN and undefined. (Unlike isNaN(x) or x == x.)
EDIT: While it is one of the use cases of x >= x, in this case (thx #Felix Kling for pointing this out) undefined is already being checked.

Categories