This expression ' ' == true returns false, which means ' ' is falsy,
However
if(' ') { console.log(' true ') } else { console.log(' false ') } ,
gets the result true.
Now I am confused, whether the string of whitespace is truthy or falsy?
The string ' ' is a "truthy" value.
Here is a list of the "falsy" values:
false
null
undefined
0
NaN
''
You have to understand that "truthy" is not the same thing as true. A value can be "truthy" without being true. For example, if we did 5 == true, we would get false, even though 5 is a "truthy" value.
In general, pretty much every value is "truthy" (excluding the ones mentioned above). But, the easiest way to check if something is "truthy"/"falsy" is by doing something like this:
var value = valueToTest;
if (value) {
console.log('Truthy!');
} else {
console.log('Falsy!');
}
Is a string of whitespace truthy or falsy?
It's truthy, as others indicated. However, your comparsion
' ' == true
is not checking whether ' ' is truthy. It's comparing two values, which is a different thing and uses specific comparison rules. The JS spec is that any == comparison with a boolean first coerces the boolean to a number:
If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
So your code is equivalent to
' ' == Number(true)
which is the same as
' ' == 1
Next, to compare a string and a number, JS converts the string to a number. Again, quoting the spec:
If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.
So we now have
Number(' ') == 1
Number(' ') is 0. The spec says:
The MV of StringNumericLiteral ::: StrWhiteSpace is 0.
So this becomes
0 == 1
which, as you found, is false. See http://ecma262-5.com/ELS5_HTML.htm#Section_11.9.3 for details.
As other answers have explained not being equal (==) to true is not the same as being falsy. Falsy is a different concept, which roughly means the value to which an expression is coerced when a boolean is required (such as the condition of an if statement) is false.
in first case expression you are comparing ' ' whitespace string with bool value true and that will surely result in false as ' ' is not equal to true.
in second case expression you are simply writing ' ' whitespace in conditional check in if statement. according to the execution rule of if statement if value is present that it will evaluate to true. and whitespace character is not null so it will execute code block for true statement.
Hope this will help.
following value will evaluated to false if directly placed inside if statement test.
false
null
nil
undefined
NaN
''
0
values other than above will evaluate to true
From your code ' ' == true you are comparing string with a boolean so its obvious those 2 things are totally different and hence you get return as false
In second case i.e. if(' ') you are checking whether you have an object or a null. Here ' ' is a valid non-null object hence you get result as true.
' ' is equal to 32 in ASCII. so , ' ' == true means 32 == true, if(' ')" means if (32).
Related
I have two statements like this. Why do they both evaluate to false?
console.log([] == true)
console.log(![] == true)
If [] == true is false shouldn't ![] == true result to true?
It's the way coercion works.
The first step of coercion is to convert any non primitive types to primitive types, then using a set of rules convert the left, right or both sides to the same type. You can find these rules here.
In your case [] == true, would pass through these 4 steps:
[] == true
[] == 1
"" == 1
0 == 1
Whereas based on operator precedence the ! in ![] == true is executed first so the expression is converted to false == true which is obviously false.
You can try the live demo by Felix Kling to better understand how the sameness operator works.
In more words:
The value ![] is false, because [] is an Object (arrays are objects) and all objects, not including null, are truthy. So any array, even if it is empty will always be a truthy, and the opposite of a truthy is always false. The easiest way to check if a value is a truthy is by using !!.
console.log("![]: " + ![]);
console.log("!![]: " + !![]);
When you are using a loose comparison (using == instead of ===) you are asking the JavaScript engine to first convert the values into the same type and then compare them. So what happens is the values get converted according to a set of rules, once they are the same type, they get compared though the same process as a strict equality check (===). The first change that [] goes through is to get converted to a string, the string version of an empty array is an empty string "", the empty string is then converted to a number, the numeric value of an empty string is 0, since the numeric value of true is 1 and 0 != 1, the final output is false.
console.log("[] == true => `" + ([] == true) + "`");
console.log("String([]) => `" + String([]) + "`");
console.log("Number('') => `" + Number("") + "`");
console.log("Number(true) => `" + Number(true) + "`");
As per the Abstract Equality Comparison Algorithm - http://es5.github.io/#x11.9.3
Types of x and y are checked when x == y is to be checked.
If no rule matches, a false is returned.
For [] == true , rule 7 matches, so a result of [] == ToNumber(true) is returned i.e. false is returned.
Reason you're getting the same result for ![] == true, because ![] returns false, and false == true returns false .
To get opposite result for your second operation, add a precedence (i.e. wrap) to your expression with braces.
console.log(!([] == true)); // returns true
Put ![] in the console. It's false.
So ![] == true is the same as false == true, which is false.
[] != true is true though
None of the answers so far has addressed the main problem. [Edit: This is no longer true. See Nick Zoum's answer.]
The question essentially is this:
[] == true returns false
=> [] is not true
=> [] is false (because something not true must be false)
=> ![] should be true, since negation of false is true. Then why does ![] == true return false?
[] is actually truthy. (So ![] is actually falsy.)
Still, [] == true returns false -- the reason is coercion. It's another of Javascript's gotchas.
When an array is checked for equality explicitly against a boolean value (that is, against true or false), its elements are first converted to strings and then joined together. An empty array therefore becomes "" — therein lies the problem, because an empty string is falsy.
In brief, an empty array is truthy, but it's coerced (when being compared to a boolean value) to an empty string, which is falsy.
Note the following, which comes from https://www.nfriedly.com/techblog/2009/07/advanced-javascript-operators-and-truthy-falsy/
Arrays are particularly weird. If you just test it for truthyness, an
empty array is truthy. HOWEVER, if you compare an empty array to a
boolean, it becomes falsy:
if ( [] == false ) {
// this code runs }
if ( [] ) {
// this code also runs }
if ([] == true) {
// this code doesn't run }
if ( ![] ) {
// this code also doesn't run }
(This is because when you do a comparison, its elements are turned to Strings and joined. Since it's empty, it becomes "" which is then falsy. Yea, it's weird.)
Read https://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/
Rule in JavaScript for The Equals Operator (==)
if
type(x) type(y) result
1.x and y are the same type See Strict Equality (===) Algorithm
2.null Undefined true
3.Undefined null true
4. Number String x == toNumber(y)
5. String Number toNumber(x) == y
6. Boolean (any) toNumber(x) == y
7. (any) Boolean x == toNumber(y)
8.String or Number Object x == toPrimitive(y)
9.Object String or Number toPrimitive(x) == y
***10.otherwise… false
Today when I was doing some experiments with ==, I accidentally found out that "\n\t\r" == 0. How on earth does "\n\t\r" equal to 0, or false?
What I did is:
var txt = "\n"; //new line
txt == 0; //it gives me true
And that really annoy me. So I did more:
var txt = "\r"; //"return"
txt == 0; //true
var txt = "\t"; //"tab"
txt == 0; //true
It does not make sense, at all. How's that happen? And more crazy is this:
//Checking for variable declared or not
var txt ="\n\t\r";
if(txt!=false){
console.log("Variable is declared.");
}else{
console.log("Variable is not declared.");
}
What it gives me is Variable is not declared.
How is it equal to 0, or false???
This behaviour might be surprising but can be explained by having a look at the specification.
We have to look at the what happens when a comparison with the equals operator is performed. The exact algorithm is defined in section 11.9.3.
I built a simple tool to demonstrate which algorithm steps are executed: https://felix-kling.de/js-loose-comparison/
string == integer
The step we have to look at is #5:
5. If Type(x) is String and Type(y) is Number,
return the result of the comparison ToNumber(x) == y.
That means the string "\n" ("\r", "\t") is converted to a number first and then compared against 0.
How is a string converted to a number? This is explained in section 9.3.1. In short, we have:
The MV (mathematical value) of StringNumericLiteral ::: StrWhiteSpace is 0.
where StrWhiteSpace is defined as
StrWhiteSpace :::
StrWhiteSpaceChar StrWhiteSpace_opt
StrWhiteSpaceChar :::
WhiteSpace
LineTerminator
This just means that the numerical value of strings containing white space characters and/or a line terminator is 0.
Which characters are considered as white space characters is defined in section 7.3.
string == boolean
The step we have to look at is #7:
7. If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
How booleans are converted to numbers is pretty simple: true becomes 1 and false becomes 0.
Afterwards we are comparing a string against a number, which is explained above.
As others have mentioned, strict comparison (===) can be used to avoid this "problem". Actually you should only be using the normal comparison if you know what you are doing and want this behaviour.
Because JavaScript is a loosely typed language, it attempts to type cast your 1st side of the comparison to the other so that they would match each other.
Any string which does not contain a number, becomes 0 when compared to an integer, and becomes true (Except in certain situations), when compared to a Boolean.
Light reading material.
txt is not a Boolean, so it will never be false. It can be undefined though.
var txt ="\n\t\r";
if(txt !== undefined) { //or just: if (txt)
console.log("Variable is declared.");
} else {
console.log("Variable is not declared.");
}
//=> will log: 'Variable is declared.'
By the way, a declared variable may be undefined (e.g. var txt;).
If you do a stricter comparison (without type coercion, using ===), you'll see that
var txt = '\n'; txt === 0; //=> false
var txt = '\r'; txt === 0; //=> false
var txt = '\t'; txt === 0; //=> false
See also
The reason is that "\n\t\r" just as " " are treated as empty strings.
If you use == it will return true but if you use === it will return false.
If you want to test for existence you should use something like
if(typeof strName !== 'undefined') {
/*do something with strName*/
} else {
/*do something without it*/
}
Whenever you use the == operator and try to compare a string to a number, the string will first be converted to a number. Thus: alert("\n\r"==0) becomes: alert(Number("\n\r")==0)
The Number constructure is kind of interesting. It will first strip whitespace then decide if the number is a not a number or not. If NaN, then the result is "NaN". If the string is empty, then the result is 0.
alert(Number()) alerts 0
alert(Number("")) alerts 0
alert(Number(" \n \r \n \t")) alerts 0
alert(Number("blah")) alerts NaN
alert(Number("0xFF")) alerts 255
alert(Number("1E6")) alerts 1000000
To check if the result is NaN use isNaN()
Thus: alert(isNaN("blah")) alerts true
Thus: alert(isNaN("")) alerts false
Thus: alert(isNaN("\n")) alerts false
Thus: alert(isNaN(" ")) alerts false
however do note that NaN will never equal NaN:
var nan=Number("geh");alert(nan==nan); alerts false
Update:
if you want to check if both sides are NaN, then you'd convert both to boolean values first like so:
var nan=Number("geh");alert(!!nan==!!nan); alerts true
or better yet
var nan=Number("geh");
alert(isNaN(nan)&& isNaN(nan));
I have two statements like this. Why do they both evaluate to false?
console.log([] == true)
console.log(![] == true)
If [] == true is false shouldn't ![] == true result to true?
It's the way coercion works.
The first step of coercion is to convert any non primitive types to primitive types, then using a set of rules convert the left, right or both sides to the same type. You can find these rules here.
In your case [] == true, would pass through these 4 steps:
[] == true
[] == 1
"" == 1
0 == 1
Whereas based on operator precedence the ! in ![] == true is executed first so the expression is converted to false == true which is obviously false.
You can try the live demo by Felix Kling to better understand how the sameness operator works.
In more words:
The value ![] is false, because [] is an Object (arrays are objects) and all objects, not including null, are truthy. So any array, even if it is empty will always be a truthy, and the opposite of a truthy is always false. The easiest way to check if a value is a truthy is by using !!.
console.log("![]: " + ![]);
console.log("!![]: " + !![]);
When you are using a loose comparison (using == instead of ===) you are asking the JavaScript engine to first convert the values into the same type and then compare them. So what happens is the values get converted according to a set of rules, once they are the same type, they get compared though the same process as a strict equality check (===). The first change that [] goes through is to get converted to a string, the string version of an empty array is an empty string "", the empty string is then converted to a number, the numeric value of an empty string is 0, since the numeric value of true is 1 and 0 != 1, the final output is false.
console.log("[] == true => `" + ([] == true) + "`");
console.log("String([]) => `" + String([]) + "`");
console.log("Number('') => `" + Number("") + "`");
console.log("Number(true) => `" + Number(true) + "`");
As per the Abstract Equality Comparison Algorithm - http://es5.github.io/#x11.9.3
Types of x and y are checked when x == y is to be checked.
If no rule matches, a false is returned.
For [] == true , rule 7 matches, so a result of [] == ToNumber(true) is returned i.e. false is returned.
Reason you're getting the same result for ![] == true, because ![] returns false, and false == true returns false .
To get opposite result for your second operation, add a precedence (i.e. wrap) to your expression with braces.
console.log(!([] == true)); // returns true
Put ![] in the console. It's false.
So ![] == true is the same as false == true, which is false.
[] != true is true though
None of the answers so far has addressed the main problem. [Edit: This is no longer true. See Nick Zoum's answer.]
The question essentially is this:
[] == true returns false
=> [] is not true
=> [] is false (because something not true must be false)
=> ![] should be true, since negation of false is true. Then why does ![] == true return false?
[] is actually truthy. (So ![] is actually falsy.)
Still, [] == true returns false -- the reason is coercion. It's another of Javascript's gotchas.
When an array is checked for equality explicitly against a boolean value (that is, against true or false), its elements are first converted to strings and then joined together. An empty array therefore becomes "" — therein lies the problem, because an empty string is falsy.
In brief, an empty array is truthy, but it's coerced (when being compared to a boolean value) to an empty string, which is falsy.
Note the following, which comes from https://www.nfriedly.com/techblog/2009/07/advanced-javascript-operators-and-truthy-falsy/
Arrays are particularly weird. If you just test it for truthyness, an
empty array is truthy. HOWEVER, if you compare an empty array to a
boolean, it becomes falsy:
if ( [] == false ) {
// this code runs }
if ( [] ) {
// this code also runs }
if ([] == true) {
// this code doesn't run }
if ( ![] ) {
// this code also doesn't run }
(This is because when you do a comparison, its elements are turned to Strings and joined. Since it's empty, it becomes "" which is then falsy. Yea, it's weird.)
Read https://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/
Rule in JavaScript for The Equals Operator (==)
if
type(x) type(y) result
1.x and y are the same type See Strict Equality (===) Algorithm
2.null Undefined true
3.Undefined null true
4. Number String x == toNumber(y)
5. String Number toNumber(x) == y
6. Boolean (any) toNumber(x) == y
7. (any) Boolean x == toNumber(y)
8.String or Number Object x == toPrimitive(y)
9.Object String or Number toPrimitive(x) == y
***10.otherwise… false
I am a bit confused with this condition:
console.log('' && false) //''
I was expecting it to return false, however it returns ''
but with empty space, it's returning false
console.log(' ' && false) //true
Could someone please explain the reason for this?
My answer was found here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators
Returns expr1 if it can be converted to false; otherwise, returns
expr2. Thus, when used with Boolean values, && returns true if both
operands are true; otherwise, returns false.
So console.log('' && false) //''
because '' can be converted to false (!!'' will return false), it will return ''
What you are receiving out of the first log, '' is not the same condition string. Check this:
console.log('' && false || 'else string')
And you will see it logs the 'else string'. Since your condition has zero length, it goes after the else which does not exist. So it simply shows an emoty string.
Zero length strings are falsy in general and that's why you get false result out of the second one.
"&&" operator evaluates the first operand and proceeds to next operand only if first operand is evaluated to some truthy value or true itself. This evaluation continues until the complete expression is evaluated.
For example, a==b && b>=7 && c==6. In this, only if a==b is true it checks b>=7 and if this evaluates to true then it checks c==6.
Here in your question, '' is an empty string and is a falsy value. Hence, it didn't proceed for the last operand and returned ''. For more information on truthy and falsy values in javascript go through this link: https://www.sitepoint.com/javascript-truthy-falsy/
This question already has answers here:
Why does ('0' ? 'a' : 'b') behave different than ('0' == true ? 'a' : 'b') [duplicate]
(6 answers)
Closed 8 years ago.
Can anyone explain why here a = [] ? 1 : 2 a will be equal to 1 and here b = [] == true ? 1 : 2 b will be equal to 2
A very similar case is handled in Why does ('0' ? 'a' : 'b') behave different than ('0' == true ? 'a' : 'b').
In short:
When you have a single value that is evaluated in a boolean context, it is passed to ToBoolean to be converted to a boolean value.
If you compare values with == though, the algorithm in section 11.9.3 of the ECMAScript specification takes place. In this algorithm, both operands are converted to either strings or numbers and these values are compared.
More detailed explanation
a = [] ? 1 : 2
The condition is converted to a boolean by calling ToBoolean(GetValue(lref)). Now I assume that for objects, GetValue just returns the object itself and all objects evaluate to true.
Since arrays are just objects, the result of this expression is 1.
b = [] == true ? 1 : 2
As already said, quite some type conversion is going on here.
First, true is converted to a number:
7. If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
false is converted to 0 and true is converted to 1.
So we have
[] == 1
Then step 9 applies:
9. If Type(x) is Object and Type(y) is either String or Number,
return the result of the comparison ToPrimitive(x) == y.
That means [] is converted to a primitive value (string or number). If you follow the ToPrimitive function (and section 8.12.8), you'll find out that arrays are converted to strings, by concatenating their elements with ,. Since an empty array as no elements, the result is an empty string.
So we end up with
"" == 1
Then step 5 applies:
5. If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.
An empty string is converted to 0, hence 0 == 1 is false and the conditional operator returns 2.
Because an array is an object, and when an object is evaluated in the context of a boolean comparison, it is "truthy", but not exactly true.
In the first example the array is being converted to a Boolean which yields true as it's not null, undefined, "", 0 or false.
In the second example you're getting a type conversion because of the equals operator. From mdn:
If the two operands are not of the same type, JavaScript converts the operands then applies strict comparison. If either operand is a number or a boolean, the operands are converted to numbers if possible.
Tried the following in the console:
Number(true) //gives 1
Number([]) //gives 0
So when converted to numbers these are not equal.
In a = [] ? 1 : 2, it returns 1 if [] is not null or undefined.
In b = [] == true ? 1 : 2, it would return 1 if [] is true, but it's not, so it returns 2.
The first is an assignment and thus has to fall through to true (but DOESN'T equate anything). Equating empty to true will be false.
Because initialising an array with [] returns true and [] == true does not :-)