+true // result: 1
true.valueOf() // result: true
+true === true.valueOf() // result: false
In Javascript Type Coersion, the function called for evaluation is valueOf(). But if the function is called explicity it returns a different value.
Type Coersion in Javascript happens if == is used, which is kinda loose comparison operator.
=== is strict comparison operator which doesn't coerce the types when comparing so it remains an integer and the other one bool
+true === true.valeOf() // false
+true == true.valueOf() // true
Docs:
The identity (===) operator behaves identically to the equality (==)
operator except no type conversion is done, and the types must be the
same to be considered equal.
Why true.valueOf() doesn't returns 1
The answer is true.valueOf returns true, which is the primitive value of a Boolean object. Also the quote is from MDN
The valueOf method of Boolean returns the primitive value of a Boolean
object or literal Boolean as a Boolean data type.
What does +true do:
+true is same as Number(true) and it is a well known fact that 0 is false and 1 is true in almost every language. In fact in C++ they are used as booleans.
the function called for evaluation is valueOf()
Not always. valueOf() is only meaningful for non-primitive types, since it is defined to return the primitive value of the given object. true by itself is a Boolean primitive and as such calling true.valueOf() would be completely redundant.
The unary + and - sign operators always return a number by definition. Since a Boolean quite conveniently converts to a number, it only makes sense that +true returns 1.
There is no reason +true and true.valueOf() should both correspond to the same value.
for strict comparison you should do like this:
Number(true.valueOf()) === +true
Related
I am wondering why the Boolean coercion fails in this case:
!!(new Boolean(false)) === true
Although:
(new Boolean(false).valueOf()) === false
Mozilla says:
Booleans are returned as-is.
I am wondering what "as-is" means in the context of a coercion. I thought "coercion" means "convert anything to a primitive boolean". How is it possible that something which is meant to be false gets coerced to true?
BTW: Consequently this fails too:
Boolean(new Boolean(false)) === true
It seems to me, that the Boolean class itself is an error. Maybe I have to use the following code:
if (arg instanceof Boolean)
throw new Error("Stop doing nonsense")
Or maybe this:
function coerce_boolean_correctly (arg) {
if (arg instanceof Boolean)
return coerce_boolean_correctly(arg.valueOf())
return !!arg
}
There is a huge difference between a Boolean object and a Boolean primitive. The MDN page you referenced, actually warns about this at the very outset:
Do not confuse the primitive Boolean values true and false with the true and false values of the Boolean object.
Any object, including a Boolean object whose value is false, evaluates to true when passed to a conditional statement.
And this (what I marked in bold) is exactly what happens in your code: it creates a new Boolean(false) and that will coerce to true -- in other words it is a truthy value. In your code you have explicitly converted it to a boolean primitive, by applying ! to it twice. In either case (implicit coercion or explicit conversion) new Boolean(false) is truthy. Fact is that all objects are considered truthy (when coerced to boolean, they evaluate to true).
The article continues with:
Do not use the Boolean() constructor with new to convert a non-boolean value to a boolean value — use Boolean as a function or a double NOT instead.
This suggests that your code should be modified to drop the use of new, and call Boolean as a plain function, not as constructor:
!!(Boolean(false)) === false
When Boolean is called as plain function, it returns a primitive boolean (false or true). But anything that is called as constructor, even Boolean, will return an object. And objects are truthy.
When in the context of coercion MDN states "Booleans are returned as-is." they refer to boolean primitives. (Boolean) objects are covered by the last bullet point in the same list: "All objects become true". The latter in includes Boolean objects.
A Boolean object has a valueOf method which returns a boolean primitive, and so it returns what you would intuitively expect.
The MDN article rightly says:
Warning: You should rarely find yourself using Boolean as a constructor.
Don't use new Boolean, but Boolean.
If for some reason you have a Boolean object, really ask yourself why you have that object in the first place. Tackle the code that created that object and use a primitive boolean from the outset.
Objects are truthy
Some are surprised in a similar way that the following holds:
if (!!new String("")) console.log("An empty string is truthy!?");
if (!!new Number(0)) console.log("The number 0 is truthy!?");
if (!!new Number(NaN)) console.log("NaN is truthy!?");
if (!!new Object(null)) console.log("null is truthy!?");
if (!!new Object(undefined)) console.log("Undefined is truthy!?");
It is the same principle: objects are truthy. Always.* No matter what their constructor is named. No matter what value was passed to that constructor.
* document.all is an abhorrent, but accepted, violation of this rule.
See also
What's the point of the Boolean object?
What is the purpose of new Boolean() in Javascript?
The following are examples that make sense to me.
isFinite(5) // true - makes sense to me, it is a number and it is finite
typeof 5 // "number"
isFinite(Infinity) // false - makes sense for logical reasons
typeof Infinity // "number"
isFinite(document) // false - makes sense as well, it's not even a number
typeof document // "object"
The following is where I get confused.
isFinite(null) // true - Wait what? Other non-number objects returned false. I see no reason?
typeof null // "object"
I just don't see the reasoning behind this.
What I'd like is the most low-level answer possible.
I think null is being converted to 0, why? What other impacts does this have?
The ECMAScript spec (5.1) defines isFinite to act as such:
isFinite (number)
Returns false if the argument coerces to NaN, +∞, or −∞, and otherwise returns true.
If ToNumber(number) is NaN, +∞, or −∞, return false.
Otherwise, return true.
In other words, isFinite is calling ToNumber on whatever's passed in, and then comparing it to either pos/neg infinity or NaN.
In JavaScript (note the use of != instead of the more common !==, causing the type cast):
function isFinite(someInput) {
return !isNaN(someInput) &&
someInput != Number.POSITIVE_INFINITY &&
someInput != Number.NEGATIVE_INFINITY;
}
(As noted in the comments below, someInput != NaN is not needed, as NaN is defined to not be equivalent to everything, including itself.)
Now, why is null converted to zero (as opposed to undefined)? As TylerH says in the comments, null means that a value exists, but is empty. The mathematical representation of this is 0. undefined means that there isn't a value there, so we get NaN when trying to call ToNumber on it.
http://www.ecma-international.org/ecma-262/5.1/#sec-15.1.2.5
However, ECMAScript 6 is bringing along a non-converting isFinite as a property of Number. Douglas Crockford suggested it here: http://wiki.ecmascript.org/doku.php?id=harmony:number.isfinite
From MDN:
The global isFinite() function determines whether the passed value is
a finite number. If needed, the parameter is first converted to a
number.
So, it's converted to a number...
isFinite(null)
isFinite(+null) //convert to a number
isFinite(0) // true because +null or Number(null) = 0
The spec says that the global isFinite() method will forcibly convert the parameter to a number.
You could, however, use (at your own risk) the EcmaScript 6 spec's Number.isFinite() which doesn't perform this conversion.
Number.isFinite(null) // false
Or, like lodash and underscore do it...
var _.isFinite = function(obj) {
return isFinite(obj) && !isNaN(parseFloat(obj));
};
isFinite calls ToNumber on its argument. So
> Number(null)
0
> Number(document)
NaN
> isFinite(0)
true
> isFinite(NaN)
false
> isFinite(null)
true
> isFinite(document)
false
Because, if you say
Number(null) === 0 which is finite
See To Number Conversions
Which says that, for argument type null result is +0
isFinite typecasts it's argument to a number, if it's not already a number. Essentially you have isFinite(Number(null)) and Number(null) === 0. Which is finite.
Beside null, you find these examples interesting too:
alert(isFinite(' ')); //true
alert(isFinite('')); //true
alert(isFinite(null)); //true
alert(isFinite(!undefined)); //true
In JavaScript implicit conversion take place, This conversion try to convert bool to integer when comparing numbers with boolean, or number to string when comparing string with numbers. If you treat any data-type as number it implicitly converted to number so all above cases return zero which is finite. See Here
If you try Number(undefined) it give you a NaN on negate this would produce a 1 which is finite.
This question already has answers here:
JavaScript: What is the difference between `if (!x)` and `if (x == null)`?
(5 answers)
Closed 9 years ago.
When I am using any one of values(null, undefined, false, '', 0) in a if statement, it is always evaluated as fallacy(false). Also, the negation of these values((null, undefined, false, '', 0) in a if statement always evaluated as tautology(true).
if(null){
}else{
}
if(undefined){
}else{
}
if(false){
}else{
}
if(''){
}else{
}
if(0){
}else{
}
In all the above cases, if statement is evaluated as false & else statement executes.
However, when I am comparing these fallacy values with == operator, it is not returning true always. Surprisingly, it is always returning true values when I am comparing the negation of these values.
if double equalto (==) operator checks/compares for values & not strictly for types, then why:
null == false // returns false
null == 0 // returns false
null == '' // returns false
But,
!null == !false // returns true
!null == !0 // returns true
!false == !undefined // returns true
And,
null == undefined // returns true
false == 0 // returns true
I appreciate if any one can clarify the behavior or relationship among these values(null, undefined, false, '', 0).
A common misconception
"...If double equalto (==) operator only checks/compares for values & not for types..."
That's an incorrect assumption, though it's often repeated by people. In reality, the == does check types, and in fact pays far more attention to the types than a === comparison does.
See Abstract Equality Comparison Algorithm.
A == comparison doesn't do a simple toBoolean conversion. Rather it walks through a somewhat complex recursive algorithm, which, after checking the types, attempts to coerce the operands to the same type if they don't match.
The type coercion that it performs is very specific to the types of the operands. A different sequence of coercions can take place for different type pairs. Usually (but not always) it ends up ultimately coercing the operands down to number types.
Why !ing the operands changes things
When you manually coerce both operands using !, you're now doing a simple toBoolean conversion causing the types to match, which avoids the type coercive part of the algorithm, making it behave essentially like the Strict Equality Comparison Algorithm.
So the only way to predict the outcome of a == comparison when the types don't match is to understand that Abstract algorithm.
Don't forget about NaN
And FYI, there's one more "falsey" value to consider, NaN. Its == comparison will always be false, no matter what. Even when comparing to another NaN value, it'll be false.
undefined: means a variable was declared but has no value assigned
null: the value of null has been assigned, which means it has no value
false, '' and 0 I think you can probably work out what these mean.
NULL is different from false (NULL is of type object and false is of type of boolean), null is different from 0 (0 is of type integer), null is also different from '' ('' is of type of string). but they are all falsy values. The ! operator negates a boolean value. If ! is used on falsy values, it results to conversion of falsy values to an object of type boolean.
I've been learning JavaScript for some time now and I know better than to actually rely on this kind of behavior but I'm getting curious... why does the empty array [] have seemingly conflicting boolean identities?
It is truthy: [] && true evaluates to true ...and yet, it is false: [] == false evaluates to true.
However, its double negation is true: !![] evaluates to true. But it's also (using loose equality) equal to its own negation: ![] == [] evaluates to true.
Its numeric value is falsy: +[] && true evaluates to 0.
Its string representation is falsy: [].toString() && true evaluates to "".
Is there any clear reason why [] is such a conundrum?
I think the results are reasonable. The only one I'm iffy on is +[], but I might have that one figured out. It's like you said, loose comparison can be misleading, but it makes sense to me.
console.log([] && true); //true - there is an array
console.log([] == false); //true, the array is empty
console.log(![]); //false, there is an array
console.log(!![]); //true, there isn't not an array
console.log(![] == []); //true, no array is loosely like an empty array
console.log(+[]); //0, I think this converts the array to a number, 0 being the logical choice. +[1] will return "1" and +[1,2] is "NaN" - which seems to be because the conversion is no longer feasible.
console.log([].toString()); //string '', as expected - also see next example
console.log(['stuff',{}].toString()); //stuff,[object Object]
I can't give you a full answer, but here are some observations:
As you know there's a Boolean function that returns a boolean value and it accepts a parameter, thus it closely resembles casting to bool. Boolean([]) returns true which explains why [] && true is true, ![] is false and !![] is true.
On the other hand the Number([]) constructor returns 0, which explains why +[] && true is zero.
Another thing is that String([]) is empty string, String(true) is the string "true" and "" && "true" is "" which perfectly fits into my grand scheme as you'll see below.
Now, about the curious things. Here's what I found out:
Number(![]) is 0, Number([]) is 0 as well. In that case Number(![]) == Number([]) is obviously true.
Number([]) is 0, Number(false) is 0, thus Number([]) == Number(false).
It seems to me that whenever JS can't directly compare two objects (neither of which are strings) it casts them to numbers and then compares. If one of them is a string it always converts to string and then evaluates any functions. At least that would explain the strange behaviour you've noticed.
&& Returns expr1 if it can be converted to false; otherwise,
returns expr2. Thus, when used with Boolean values, && returns true if
both operands can be converted to true; otherwise, returns false.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators
In your case
+[] // 0 - is falsy so it will be returned
[].toString() // "" - is falsy so it will be returned
I understand what the double not operator does in JavaScript. I'm curious about it's use though and whether or not a recent assertion that I made is correct.
I said that if (!!someVar) is never meaningful nor is (!!someVar && ... because both the if and the && will cause someVar to be evaluated as a boolean so the !! is superfluous.
In fact, the only time that I could think of that it would be legitimate to use the double not operator is if you wanted to do a strict comparison to another boolean value (so maybe in return value that expects true or false explicitly).
Is this correct? I started to doubt myself when I noticed jQuery 1.3.2 used both if (!!someVar) and return !!someVar && ...
Does the double not have any actual effect in these situations?
My personal opinion is that it just leads to confusion. If I see an if statement, I know it's evaluating it as a boolean.
In the context of if statements I'm with you, it is completely safe because internally, the ToBoolean operation will be executed on the condition expression (see Step 3 on the spec).
But if you want to, lets say, return a boolean value from a function, you should ensure that the result will be actually boolean, for example:
function isFoo () {
return 0 && true;
}
console.log(isFoo()); // will show zero
typeof isFoo() == "number";
In conclusion, the Boolean Logical Operators can return an operand, and not a Boolean result necessarily:
The Logical AND operator (&&), will return the value of the second operand if the first is truly:
true && "foo"; // "foo"
And it will return the value of the first operand if it is by itself falsy:
NaN && "anything"; // NaN
0 && "anything"; // 0
On the other hand, the Logical OR operator (||) will return the value of the second operand, if the first one is falsy:
false || "bar"; // "bar"
And it will return the value of the first operand if it is by itself non-falsy:
"foo" || "anything"; // "foo"
Maybe it's worth mentioning that the falsy values are: null, undefined, NaN, 0, zero-length string, and of course false.
Anything else (that is not falsy, a Boolean object or a Boolean value), evaluated in boolean context, will return true.
Yes, !!var is used when you want 0||1 return value.
One is simple comparison of bool values, when you want "a == b" be equivalent of "a xor not b" except a=5 and b=7 would both be true but not be equal.
Another is when you want to coerce a set of conditions into bits of a variable:
var BIT_NONEMPTY=1;
var BIT_HASERRORS=2;
var BIT_HASCHILDREN=4;
var BIT_HASCONTENT=8;
result_bitfields =
(!!countLines())*BIT_NOTEMPTY +
(!!errorCode())*BIT_HASERRORS +
(!!firstChild())*BIT_HASCHILDREN +
(!!getContent())*BIT_HASCONTENT;
Not very useful in Javascript which lives pretty far from bit values, but may be useful at times.