Consider empty JavaScript array:
var a = [];
alert(a == false); // shows true
alert(!a); // shows false!
How to explain this?
What are the rules?
From http://forums.whirlpool.net.au/archive/966449:
a == false:
In this case, the type of the left-hand side is object, the type of the right-hand side is boolean. Javascript first converts the boolean to a number, yielding 0. Then it converts the object to a "primitive", yielding the empty string. Next it compares the empty string to 0. The empty string is converted to a number, yielding 0, which is numerically equal to the 0 on the right-hand side, so the result of the entire expression is true.
See ยง11.9.3 of the ECMAScript spec for all the gory details.
(!a):
In this case Javascript converts the object to the boolean true, then inverts it, resulting in false.
The ! operator checks whether its operand is "falsy".
The following are true:
!false
!0
!null
!NaN
!undefined
!""
The == operator checks for loose equality, which has nothing to do with falsiness.
Specifically, a == b will convert to operands to numbers, then compare the numbers.
Strings containing numbers convert to the numbers that they contain; booleans convert to 0 and 1.
Objects are converted by calling valueOf, if defined.
Thus, all of the following are true:
"1" == 1
"0" == false
"1" == true
"2" != true
"2" != false
({ valueOf:function() { return 2; } }) == 2
({ valueOf:function() { return 1; } }) == true
The == operator when one of the operands if Boolean, type-converts the other to Number.
[] == 0;
Is equivalent to:
0 == 0;
You can see the complete details of The Abstract Equality Comparison Algorithm on the specification.
As you can see, an empty array object, when converted to Number, produces 0:
+[]; // 0
Number(0);
This is really because its toString method produces an empty string, for example:
[].toString(); // ""
+""; // 0
Number(""); // 0
When comparing an object to a primitive value via the == operator, the object coerces into an primitive value itself (number or string). In this case [] coerces into 0, then false coerces into 0:
[] == false
0 == false
0 == 0
which is true.
The ! operator coerces into boolean and then inverts the value. [] into boolean is true (like with any object). Then invert to become false
![]
!true
false
Not sure if this answers the question, but there is a new library for getting around all of Javascript's Typecasting weirdnesses:
Typecast.js
In a sentence, Typecast solves all the simple problems, so you can focus on the big ones. Typecast fixes what's wrong with Javascript by creating a complete platform for strongly-typed variables in Javascript.
Related
MDC describes the == operator as follows:
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; else if either operand is a string, the other operand is converted to a string if possible.
With this in mind, I would evaluate "true" == true as follows:
Are they of the same type? No
Is either operand a number or boolean? Yes
Can we convert both to a number? No (isNaN(Number("true")) // true)
Is either operand a string? Yes
Can we convert the other operand to a string? Yes (String(true) === "true" // true)
I've ended up with the strings "true" and "true", which should evaluate to true, but JavaScript shows false.
What have I missed?
Because "true" is converted to NaN, while true is converted to 1. So they differ.
Like you reported, both are converted to numbers, because at least true can be (see Erik Reppen's comment), and then compared.
The == comparison operator is defined in ECMA 5 as:
If Type(x) is Number and Type(y) is String,
return the result of the comparison x == ToNumber(y).
If Type(x) is String and Type(y) is Number,
return the result of the comparison ToNumber(x) == y.
If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
So, "true" == true is evaluated as:
"true" == ToNumber(true) (via rule 7)
"true" == 1
ToNumber("true") == 1 (via rule 5)
NaN == 1
===> false
Acording to The Abstract Equality Comparison Algorithm
http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3
if one of the oprends is a boolean and other is not, boolean is converter to number 0 or 1. so true == "true" is false.
The equality operators (== and !=) use the Abstract Equality Comparison Algorithm to compare two operands.
"true" == true
Since "true" is String and true is Boolean, we need to return the result of "true" == Number(true) (step 7 in the algorithm), which is "true" == 1.
"true" == 1
Since "true" is String and 1 is Number, we need to return the result of Number("true") == 1 (step 5 in the algorithm). Number("true") returns NaN.
Now we have NaN == 1.
NaN == 1
Now both operands are of the same type (Number).
Acording to the algorithm, if both operands are Number and one of them is NaN, false is returned (step 1.c.i in the algorithm).
Explaining considering the scenario true == "true".
Straightway, the above returns false, however, our expectation was true
JavaScript uses Abstract Equality Comparison Algorithm, so according to the algorithm
true == "true"
// If one of the operands is Boolean, convert the Boolean operand to 1 if it is true and +0 if it is false
ConvertToNumber(true) == "true"
1 == "true"
// When the algorithm finds the above statements, it thinks that it needs to do one more conversion -
// "When comparing a number to a string, try to convert the string to a numeric value"
1 == ConvertToNumber("true)
1 == NaN
// Which returns false
in PHP:
$var=0;
$var="";
$var="0";
$var=NULL;
to verify if $var is 0 or "0" or "" or NULL
if (!$var) {...}
in jQuery/JavaScript:
$var=0;
$var="";
$var="0";
$var=NULL;
if (!$var) works for every value except for "0"
Is there a general way in JavaScript/jQuery to check all kinds of those empty/null/zero values, exactly like php does?
Is there a general way in JavaScript/jQuery to check all kinds of those empty/null/zero values, exactly like php does?
No. In PHP, the values converted to booleans produces different results than in JavaScript. So you can't do it exactly like PHP does.
Why not be (a bit more) explicitly about it which makes your code easier to understand?
// falsy value (null, undefined, 0, "", false, NaN) OR "0"
if (!val || val === '0') { }
The abstract operation ToBoolean converts its argument to a value of type Boolean according to Table 11:
Undefined false
Null false
Boolean The result equals the input argument (no conversion).
Number The result is false if the argument is +0, -0, or NaN; otherwise the result is true.
String The result is false if the argument is the empty String (its length is zero);
otherwise the result is true.
Object true
0 will return false.
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
Number(variable) seems to produce expected output
Number(0) = 0
Number("0") = 0
Number("") = 0
Number(null) = 0
Number(false) = 0
If you feel funky (just in your exact case-sample) you can do this:
(otherwise undefined and NaN will result as false)
+v===0
Example:
var a = [0, "", "0", null];
var b = [1, "a", "1", {}];
a.forEach(function(v){
console.log( +v===0 ); // true, true, true, true
});
b.forEach(function(v){
console.log( +v===0 ); // false, false, false, false
});
First of "0" isn't false, its true. Because '0' is a string. Strings if they exist return true. So
!"" should return false. That said if your data is returning zeros as strings you can use:
parseInt("0", 10);
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt
This will return the integer value or NaN.
!NaN will return true, and if it is an number of say... 0 it will return !0 so you could do this:
function nullOrEmpty(value) {
return (!value && !parseInt(value));
}
You could very well use a double negative.
var test = 0;
console.log(!!test);
var test = "";
console.log(!!test);
var test = "0";
console.log(!!test);
var test = null;
console.log(!!test);
Although "0" is not an empty string so it evaluates to true, the rest return false.
Also, I agree with the comment that dfsq made in that you shouldn't rely on this. You should know and understand what types your variables are holding.
What rules apply for the JavaScript relational comparison operators when the operands are of different types?
For example, how is true > null evaluated? I can type this into my developer console and it gives the result true, but why?
I searched for a bit, but didn't find any blog posts explaining this, although there are plenty explaining type coercion for == and === comparison operators.
JavaScript relational comparison operator type coercion is defined in the JavaScript specification, specifically in sections 11.8 to 11.8.5 which describe the operators, and sections 9.1 (ToPrimitive) and 9.3 (ToNumber) which describe the process of coercing the operands.
In short, the 4 comparison operators (<, >, <=, and >=) do their best to convert each operand to a number, then compare the numbers. The exception is when both operands are strings, in which case they are compared alphabetically.
Specifically,
If an argument o is an object instead of a primitive, try to convert it to a primitive value by calling o.valueOf() or - if o.valueOf wasn't defined or didn't return a primitive type when called - by calling o.toString()
If both arguments are Strings, compare them according to their lexicographical ordering. For example, this means "a" < "b" and "a" < "aa" both return true.
Otherwise, convert each primitive to a number, which means:
undefined -> NaN
Null -> +0
Boolean primitive type -> 1 if true, +0 if false
String -> try to parse a number from the string
Then compare each item as you'd expect for the operator, with the caveat that any comparison involving NaN evaluates to false.
So, this means the following:
console.log(true > null); //prints true
console.log(true > false); //prints true
console.log("1000.0" > 999); //prints true
console.log(" 1000\t\n" < 1001); //prints true
var oVal1 = { valueOf: function() { return 1; } };
var oVal0 = { toString: function() { return "0"; } };
console.log(oVal1 > null); //prints true
console.log(oVal0 < true); //prints true
console.log(oVal0 < oVal1); //prints true
in javascript,
var a = '';
var b = (a) ? true : false;
var b will be set to false.
is this a defined behavior that can be relied upon?
Yes. Javascript is a dialect of ECMAScript, and ECMAScript language specification clearly defines this behavior:
ToBoolean
The result is false if the argument is the empty String (its length is zero);
otherwise the result is true
Quote taken from http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
Yes. All false, 0, empty strings '' and "", NaN, undefined, and null are always evaluated as false; everything else is true.
And in your example, b is false after evaluation. (I think you mistakenly wrote true)
var a = '';
var b = (a) ? false : true; // fixed!
console.log(b); // => true
var b will be set to true.
is this a defined behavior that can be relied upon?
As answered above, yes, that is the defined behavior of an empty string in a conditional (an if expression, ||, &&, ? :, ...). (The standard says that the internal ToBoolean operation must be applied.)
The evaluation is different when the empty string is used in a comparison (see Truth, Equality and JavaScript), even though the results are mostly the same:
// conditional (note: evaluation to false prints false here!)
console.log('' ? true : false); // zero length => false
// comparisons
console.log('' == true); // +0 === 1 => false
console.log('' == false); // +0 === +0 => true
console.log('' === true); // different types => false
console.log('' === false); // different types => false
Explanation: Essentially, when the operands of == have different types, JavaScript tries hard to convert them to Numbers, according to their value, (using operations the standard calls ToNumber and ToPrimitive), and then it internally applies ===. But when you use === directly, the types are not converted, so comparing a String to a Boolean is always false.
Roughly speaking, JavaScript conditionals (ToBoolean) test for a defined, non-null, non-zero, non-empty, non-false value (an empty String is ... empty, the Numbers -0 or +0 are ... zero, NaN is not a defined number, but an empty Object is apparently not really empty), or as I like to think, conditionals test for a (true) thing, while == compares the apparent, carefully converted values (ToPrimitive, ToNumber) of its operands, and === looks for exact sameness.
if (X) {} // is X a (true) thing?
if (X == Y) {} // are the values of X and Y same-ish?
if (X === Y) {} // are X and Y exactly the same?
There are more examples in Truth, Equality and JavaScript where this distinction really matters, e.g. '0' is true in a conditional (non-zero length, or, it is a thing), but false in a == comparison (the value is zero). '1' again, is true in both cases (it is a thing and has a non-zero value).
console.log('' ? true : false); // zero length => false
console.log('' == true); // +0 === 1 => false
console.log('0' ? true : false); // non-zero length => true
console.log('0' == true); // +0 === 1 => false
console.log('1' ? true : false); // non-zero length => true
console.log('1' == true); // 1 === 1 => true
var b will be set to true. This is because an empty string counts as a 'falsey' value in JavaScript as do some other values.
Please look at http://www.sitepoint.com/javascript-truthy-falsy/ for falsy values
Examples of expressions that can be converted to false are those that
evaluate to null, 0, the empty string (""), or undefined.
(see MDN Reference)
Yes, you can rely on that behavior.
A shorter way to write it will be:
var b = !!a;
Code-snippet 1:
if ( !x ) { /* do stuff */ }
Code-snippet 2:
if ( x == 0 ) { /* do stuff */ }
For what values of x do these two code-snippets differ?
I am asking because, although I read the chapter on == in the spec, I still find it hard to deal with situations like the above (where it is combined with ToBoolean coercion).
btw, I want to know this just for the sake of knowing it (I want to understand the language), so don't bother telling me about === or asking me what x is.
Update: I corrected the fist snippet. I meant !x.
[] == 0 is true; ![] is false
null == 0 is false; !null is true
NaN == 0 is false; !NaN is true
undefined == 0 is false; !undefined is true
!x will check whether x is "falsy".
x == 0 will check whether x is "equivalent to" 0.
Both of these terms are defined by the Javascript spec.
The following will give you true for the first and false for the second snippet:
NaN
null
undefined
And these will give you false for the first and true for the second snippet:
[]
"0" and any other string that converts to 0 using Number(x) such as "00", "000", "+0", and "-0" (which I will now call "noughty strings")
an array containing a single element that is 0, null, undefined or an empty or noughty string.
For everything else you'll get the same result for both snippets, although there may be one or two more cases I haven't thought of.
Here's an interesting one with regard to a non-empty String that has only space characters:
!!" "; // true
" " == true; // false
This is because when you do a == comparison, and one of the values being compared is a number or a boolean, an attempt is made to convert the other value to a number.
The reason you get the different result is that a string with only space characters converts to the number 0 (or falsey), while a string with only spaces converted to boolean via !! is seen as a non-empty string, and therefore true.
So:
var x = " ";
alert( !x ); // false
alert( x == 0 ); // true
EDIT:
Probably the key thing to remember is that when comparing a number or boolean to a non number type, == uses toNumber conversion if possible, while ! uses toBoolean conversion. They're not always the same.
It is easy to see the result of the toBoolean conversion using !!. As in:
alert( !![] ); // true
But you can't really see the result of the toNumber conversion when using ==.
You can, however, use the unary + to see the result of a toNumber conversion. As in:
alert( +[] ); // 0
I'm pretty sure that what happens in the case of an Array, is that it first gets a toString call. Therefore:
// ---------------------toString result-------toNumber result (from string)
alert( +[] ); // "" 0
alert( +[""] ); // "" 0
alert( +[" "] ); // " " 0
alert( +[0] ); // "0" 0
alert( +["0"] ); // "0" 0
alert( +["3"] ); // "3" 3
alert( +[3,4] ); // "3,4" NaN
Short answer: the two are almost always the same but not 100% the same.
An example would be (!'0') which is false whereas ('0' == 0) is true
Details:
From: http://www.joeyjavas.com/2007/08/04/javascript-true-false-checking-for-boolean-values/
Checking if a value is true or false is simple in JavaScript. All values evaluate to true, except for:
0
-0
null
undefined
NaN
empty string
false
Therefore, (!x) will be true for all of the above values of x and only those.
As for (x == 0), it will be true for any value of x which - when converted according to "==" conversion rules - is converted to 0 when compared to a number (for example, Boolean false value). Other examples that compare true to ==0 are objects which generate 0 from their valueOf() methods, or a string '0', or an empty Array ([])
The first test will succeed when x is non-zero, or evaluates to an object (as opposed to null or undefined), or is a non-empty string. So if x is 0 then the condition fails, but if it is "0" then it succeeds.
The second test will succeed when x is convertible to 0. This means it must not be null, undefined, or an object to pass this test. And it may be "0" or "".
In other words, these conditionals are not opposites. The value "0" will pass both tests, for example.
Code Snippet 1 will execute if x is "falsy" value. In Javascript, this means 0, -0, null, undefined, NaN, "", or false. Code Snippet 2, however, will only execute if x is zero. Unlike the first condition, this does not include other "falsy" values.
The difference between the two is that
if ( x ) { ... }
Tests whether x is "truthy"
Whereas
if ( x == 0 ) { ... }
Does type coercion between x and 0.
I presume you mean something like
if (x == 0) vs if (!x)
The main difference is type coercion of x to a number vs checking if x is falsy.
Clearly NaN itself will never equal 0 since its not a number. undefined will also coerce to NaN so that is not caught by == 0 I can't give a good explanation why null is not caught by 0 since Number(null) == 0
After some lookups, have to change my awnser.
There's no simple logic, implicit equality operations follows an algorithm.
http://interglacial.com/javascript_spec/a-11.html#a-11.9.3
I can't sum it up better then what the algoritm describes, it would just get more confusing.
So it's (!x) is equivalent to (typeof x === false) aka (not true)
And (x == 0) gets compared by algorithm.