Difference between equality checking inside 'if condition' vs 'console.log' [duplicate] - javascript

This question already has answers here:
Empty arrays seem to equal true and false at the same time
(10 answers)
Closed 4 years ago.
I was trying out a code snippet and the results are different for an empty array check inside a console.log statement and in a conditional statement.
Help/Thoughts on why this is different?
Thanks in advance!
//Output: true
if([]) {
console.log(true)
} else{
console.log(false)
}
//Output: false
console.log([] == true)

You seem to be running into a known JavaScript quirk.
"[] is truthy, but not true"
The problem isn't where you are doing the evaluations, but rather that the two evaluations which seem identical are actually different.
See
https://github.com/denysdovhan/wtfjs#-is-truthy-but-not-true

My assumption is that the if/else block, in part of its "truthful" test is checking if something exists (not just if it is true or not) -- wherein the straight console print is comparing the value of the empty array against a boolean (which would be false)
let test = 'apple';
if( test ){
console.log( 'if/else: ' + true );
}else{
console.log( 'if/else: ' + false );
}
console.log( 'log: ' + ( test == true ) );

The two snippets are actually doing different things, hence the different results.
The first, with [] as the condition of the if statement, coerces the array to a Boolean value. (if, naturally enough, only works on Booleans, and JS will happily convert the given value if it isn't already Boolean.) This produces true - all objects in JS are "truthy", which includes all arrays.
For the second snippet, you are using the "loose equality" operator == - for which the JS specification provides a set of rules for how to convert the values into other types, eventually reaching a straightforward comparison between two values of the same type. You might want, or hope, that comparing a non-Boolean to true or false in this situation coerced the non-Boolean to Boolean - but this isn't what happens. What the specification says is that first the Boolean is coerced to number value - resulting in 1 for true (and 0 for false). So it reduces to [] == 1 - which will go through a few more conversions before resulting in a false result.
The key point is that no conversion to Boolean happens in the second case. If you think this is stupid, you're probably right. This is a bit of a gotcha, and one of the reasons many guides tell you never to use == in JS. I don't actually agree with that advice in general (and hate linters telling me to always use === in any circumstances) - but you do have to be aware of some dangers. And using == to compare a value to true or false is something to always avoid.
Luckily, if you want to test if x is truthy or falsy, you have a very short and understandable way to do it - the one you used in the first snippet here: if (x)

[edit] So my original answer was confusing as heck, and there are some incongruencies in the many answers you find on this subject all over the internet; so, let me try this again:
Part 1: Why they are Different
if([]) and if([] == true) are not the same operation. If you see the below example, you will get the same result when doing the same operation.
//Output: false
if([] == true) {
console.log(true);
} else{
console.log(false);
}
//Output: false
console.log([] == true);
Part 2: Why it matters AKA: the confusing bits
In JS, the following is a common expression used to see if an object/variable exists:
var foo = "Hello World";
if (foo) ...
From a design perspective, this test is not important to see if foo is equal to true or false, it is a test to see if the program can find the object or variable foo. If it finds foo, then it executes the results in the "then" condition, otherwise you get the "else" condition. So, in this case, it will convert foo to either false for does not exist, or true for does exist. So in this case the string is reduced to a boolean.
In contrast:
var foo = "Hello World";
if (foo == true) ...
Is typically trying to find out if the value of foo actually equals true. In this case, you are comparing the value of foo "Hello World" to a boolean, so in this case, "Hello World" does not equal true.
Just like foo, [] can be evaluated more than one way. An empty array is still an object; so, in the first case, it coerces to true because it wants to know if [] can be found; however, [] also equals ['']. So now picture this:
if (['bar'] == 'bar') ...
In this case, JS will not look at ['bar'] to see if it is there, but as an object containing a single value which it can convert to the string, 'bar'.
So:
if([]); // is true because it is an object test that evaluates as (1 === 1)
and
if([] == true) // is false because it is a string test that evaluates as ('' == 1) to (0 === 1)

Related

Shortened if statements and their direct equivalents in JavaScript

I've been studying JavaScript for a couple months, and I have some questions.
Say we have some if statements like this:
if (something)
if (!something)
From what I have looked up, the first statement checks whether something evaluates to true, whereas the second one checks for whether the condition is not true(I recall reading the ! coerces it into boolean and then 'inverses' it).
However, I'd like to know what are these statements' direct equivalents when not "shortened". I'd like to understand code like this more in depth before really using it.
Is if (something) the same as if (something == true)? Or even if (something === true)?
And what would be the "non-shortened" (for my lack of a better term) direct equivalent of if (!something)?
Thank you for any help.
Part 1:
When we use if(something) javascript will check if it is a 'Truthy' or 'Falsy' value.
So if we say
if(1) {
alert("Yes, it's true...");
}
javscript will check if 1 is a "truthy" value and it is.
Everything that is not a falsy value is truthy by extension.
Falsy values are:
0, 0n, null, undefined, false, NaN, and the empty string “”.
So if we directly put any of the above into a parenthesis it will return false.
e.g. if (null) ... the if clause won't be executed because null is falsy.
Part 2:
When we use if(something == true), we check if one value is equal to another value. If the types are not the same, since we're using == coercion will happen.
What is this about 'coercion'?
If we say if('1' == 1) this will execute the if clause as it returns true. Javascript will convert 1(number) to '1'(string) in this case.
If we want to be strict and say "I only want true if they're both numbers, I don't care if 1 is a string" then we use
if(1 === '1') and this will not execute the if clause(because the condition returns false).
So if we say if(false == false) this will return true because false is equal to false, and the if clause will be executed.
Note the difference if we said if(false) or if('') the if statement will not be executed.
Next, if we want to use negation, we have to put the ! in front of the boolean we're negating, regardless of whether it's part of an if condition or... There is no way around it.
However, there is a shorter version of this:
var a = 3;
var b = 2;
if(a===b) {
alert('A is equal to B');
} else {
alert('B is not equal to A');
}
This is considered shorter(ternary operator):
Note that if we want to use more than one statement, we should use the if else
a = 3;
b = 2;
a===b ? alert('A is equal to B') : alert('B is not equal to A');

Difference Between ! and != in JavaScript [duplicate]

This question already has an answer here:
What does this symbol mean in JavaScript?
(1 answer)
Closed 4 years ago.
In JavaScript, what is the difference between doing:
if (a !b)
{
// something here
}
and
if (a != b)
{
// something here
}
I know that '!' is 'logical not' and '!=' is 'not equal to', but I am not sure on the difference between the two.
I have seen both examples used on SoloLearn projects though.
Neither of the above give any errors or warnings in my web browser (chrome).
I'm not sure how to use chrome's debug console yet.
I don't mean "difference between !== and !===" btw.
In JavaScript !foo is a boolean toggle so if foo = true; then !foo is checking to see if foo equals the opposite value in this case false,
your function:
if (a !b)
{
// something here
}
doesn't do anything, and should actually just be:
if (!b)
{
// something here
}
which tests to see if bis in the opposite state.
When you use != you are comparing two values to see if one doesn't equal to the other.
so your function:
if {a != b)
{
// something here
}
checks to see if a doesn't equal b.
Cheers.
A plain ! is a logical operator and indicates opposite. For example a common practice for toggling a boolean operator when you don't always know the current state would be the following:
// Toggle Foo, regardless of current value, assuming its of a boolean type.
var foo = !foo;
!= is an inequality operator and is used to test for "not equal" operator, it simply checks whether something is equal to whatever you are comparing it to.
Here is a great question about this in a more broad context.

Why I'm not getting an error when checking the length of null [duplicate]

This question already has answers here:
Does a javascript if statement with multiple conditions test all of them?
(10 answers)
Closed 6 years ago.
I'm checking the number of digits in a string using the match and length properties. Here is the codepen with my function http://codepen.io/PiotrBerebecki/pen/redMLE
Initially when returning numberOfDigits.length I was getting an error message (Cannot read property 'length' of null). I've solved this issue by changing the line to (numberOfDigits && numberOfDigits.length).
This works but I would like to get a better understanding why the new statement can be executed now. Does the interpreter execute the `numberOfDigits.length now?
Also, why are we getting the same errors when the operands are reversed (numberOfDigits.length && numberOfDigits)?
Here is the full JavaScript code:
function checkLength(str) {
let numberOfDigits = str.match(/\d/g);
return (numberOfDigits && numberOfDigits.length);
}
console.log( checkLength('T3xt w1th sOme numb3rs') );
console.log( checkLength('Text with some numbers') );
UPDATE 1:
The answers below explained that:
The order of the operands in the && expression counts.
JavaScript optimises the && operator and if the first operand evaluates to null then JavaScript does not check the second one as the expression cannot evaluate to nothing else than null / false.
JavaScript tries to optimise the && operator:
numberOfDigits && numberOfDigits.length
If numberOfDigits is a falsy value (and null is falsy), then the entire expression will be falsy and there is no need to evaluate numberOfDigits.length.
Falsy values are: undefined, null, 0, '', false, NaN. One way to check if something is falsy is to use the Boolean(falsyValue) === false (or more practical but less verbose ! falsyValue).
This is a side effect of the && operator. I can recommend to avoid using it and transform the code to something readable:
function checkLength(str) {
let numberOfDigits = str.match(/\d/g);
return Array.isArray(numberOfDigits) ? numberOfDigits.length : 0;
}
"Does the interpreter execute the `numberOfDigits.length now?"
No, JavaScript short-circuits logical expressions - as soon as result is known (i.e. first operand in and is falsy or first operand in or is truthy), no further operations are executed in the expression.
Docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators
also, beware: && and || do not necessarily return Booleans in JavaScript
the reason is that when the interpreter sees two operations connected with a logical and (&&) it will first execute the former, and only if it is evaluted to true then it will execute the latter.
that is why since it found numberOfDigits to be null, which in JS is equivalent to false, it stops execution and never crashes on numberOfDigits.length.
the other way around will, of course, crash.
on a logical OR (||) the interpreter will stop evaluating after the first statement to be true.
I believe the reason is that the order of conditions counts.
The numberOfDigits condition gets evaluated first, so if that is false, the rest of the conditions are not evaluated and you won't get an error.
In the other order you would try to read "length" property of null, generating an error.
"And" logic will be executed as below.
true & true = true
false & anything = false`
If first condition fails then there is no point of executing second one.
so it wont execute numberOfDigits.length if numberOfDigits is null or undefined so no error in the below case.
(numberOfDigits && numberOfDigits.length) => false
false && anything => false
In same way if first condtion is not null then it will execute second condition.
(numberOfDigits && numberOfDigits.length) => true
true && true (must be) => true
Note : In javascript null and undefined are interpreted as false
in conditional statements.

Javascript how to use the and/or operator with parenthesis

I have an object that contains a string HelloWorld in the attribute hello. I want to check for two strings, and if it does not match with either one, then I want to execute certain code.
var item = { hello: "HelloWorld" }
item.hello !== "HelloWorld" && item.hello !== "GoodbyeWorld" // false, correct
However, I feel this can be optimized and made more readable:
item.hello !== ("GoodbyeWorld" && "HelloWorld") // false, correct
item.hello !== ("HelloWorld" && "GoodbyeWorld") // true WTF?
I expected both checks to be falsy, but surely I'm missing something here. I think I do not have a correct understanding of the AND/OR operator in javascript, or I am using the parenthesis in a wrong manner. Can anyone explain?
JSFiddle example
The result of "HelloWorld" && "GoodbyeWorld" is "GoodbyeWorld" which is why you're getting the result you are, the previous way you were doing it is the simplest solution
Let's take a look at this line
item.hello !== ("HelloWorld" && "GoodbyeWorld") // true WTF?
The logical AND operator evaluates its right operand, if lVal is a truthy value.
Note, a truthy value is every value which is not falsy (null,false,0,"",undefined,NaN)
Since "HelloWorld" is indeed truthy
The expression ("HelloWorld" && "GoodbyeWorld") evaluates to "GoodbyeWorld" and you're effectively comparing
item.hello !== "GoodbyeWorld" which can be reduced to "HelloWorld" !== "GoodbyWorld"
Hence, is true
However, if you're on an ES5 compatible environment you could use Array.prototype.indexOf to simplify it.
!~["HelloWorld","GoodbyWorld"].indexOf(item.hello) //false
the above returns true if item.hello is not contained in the array
No, you can't optimise the expression that way. What you are doing is elliminating one of the strings, so that you are only doing one of the comparisons.
The && operator uses short circuit evaluation, which means that if the first operand is truthy, it will just return the second operand.
So, what your code is doing is to compare the hello property value to the second one of the strings, which explains the results that you get.
item.hello !== "HelloWorld" && item.hello !== "GoodbyeWorld"
is the proper way to test whether item.hello is distinct from "HelloWorld" and "GoodbyeWorld".
An expression A && B in JavaScript yields a result which is either A or B and it's that result, that is compared to your item.hello.

Falsey values in JavaScript

I had an interesting interview question today that stumped me a little. I was asked about falsey values. So undefined, NaN, null, 0, and an empty string all evaluate to false. What is the reason this is useful to know in JavaScript? The only thing I can think of is instead of having to do this:
if (mystring === '' || mystring === undefined) { }
I can do this:
if (!mystring)
Is this the only useful application?
One dangerous issue of falsey values you have to be aware of is when checking the presence of a certain property.
Suppose you want to test for the availability of a new property; when this property can actually have a value of 0 or "", you can't simply check for its availability using
if (!someObject.someProperty)
/* incorrectly assume that someProperty is unavailable */
In this case, you must check for it being really present or not:
if (typeof someObject.someProperty == "undefined")
/* now it's really not available */
Also be aware that NaN isn't equal to anything, even not to itself (NaN != NaN).
There are two separate issues with 'falsey' values in JavaScript.
Firstly there is the official conversion scheme, which is what is returned by Boolean(x). This returns false when x is false or 0 or NaN or null or undefined or "" and true otherwise. This is the same behaviour as the
if (condition) {/*true path*/} else {/*false path*/}
that is, the false path is executed if Boolean(condition) would have returned false and the true path is executed otherwise. This behaviour is often used to check to see if a property is defined. However, doing that is not safe unless you are certain that the property would be an object or an array if it is defined. The safest way to test if a property is defined is to do
if (property != null) { /*property is defined*/}
which makes sure that the property is not null or undefined. If you only want to make sure the property is not undefined do
if (property !== undefined) { /*property is not undefined (but may be null)*/ }
(notice the extra = in !==).
Secondly, there are all the values that == false. This is everything that can be coerced to 0 (which is what false gets coerced to). This includes all the values that convert to false except NaN (which can't == false by virtue of it never == anything), null and undefined. But it also includes all objects that when converted to a string and then converted to a number are equal to 0. For example, this includes everything that when converted to a string is either the empty string "" or "0" or "-0" or "+0" or "0x00" or "000" or "0e0" or "0.0000"...., for example,
({toString: function() {return "-00.0e000";}}) == false
is true. Interestingly, this includes the empty array, and any nesting of arrays containing only a single other item that returns an empty or 0 string since arrays rendered as strings show only the contents without the surrounding brackets. That is,
[[[[0]]]] == false; // Because [[[[0]]]].toString() === "0"
[] == false;
[[[""]]] == false;
["0"] == false;
[[({toString: function() {return "0";}})]] == false;
The full algorithm for calculating == false is described here.
The reason this matters is because it can lead to subtle, difficult to find bugs if you don't understand most of these rules. Most important takeaways are probably how the if (condition) works and that using === avoids most of the other crazy stuff.
It's important to understand how this works in JS, so you're not surprised. Not necessarily just what is falsey, but what is truthy and how they compare to each other.
One example is that '0' is considered equal to 0 with ==, but it is not equal to '' - though 0 is. JavaScript comparison isn't always transitive.
So this means that just because (foo==bar && bar==fizz) is true, (foo==fizz) is not always true. To go with the above example, '0'==0, and 0=='', but '0'!='' - because you're comparing strings in the latter instance, so they are compared as strings and not coerced to numbers.
It is important to know that 0 evaluates to false to prevent doing things like:
if(str.indexOf('foo'))
It's useful to detect if a browser is has specific predefined objects:
if(!!navigator.geolocation){
// executes if the browser has geolocation support
}
if(!!document.createElement('canvas').getContext){
// executes if the browser supports <canvas>
}
Explanation: navigator.geolocation is an object or undefined. In the case it's an object !navigator.geolocation will return false, if it's undefined it'll return true. So, to check if a browser has geolocation enabled, you want to 'flip' the boolean once more, by adding another !.
They're also useful for setting default values...
function foo(bar){
alert(bar || "default");
}
I know a lot of people try to do
if (typeof(foo) === "undefined"){}
to get around falsiness, but that's got its own problems because
typeof(null) === "object"
for some reason

Categories