Why doesn't empty string == null in JavaScript - javascript

I understand that both empty string and null are falsy according to the ECMAScript. If both are falsy then why doesn't the following evaluate to true?
var emptyString = '';
if (emptyString == null) {
console.log('emptyString == null');
}
else {
console.log('emptyString does not == null'); // but why?
}

both empty string and null are falsy
Yes, but that doesn't mean all falsy values would be equal to each other. NaN and 0 are both falsy as well, but they're definitely not equal. The reverse doesn't hold either, "0" == 0 but "0" ain't falsy.
The sloppy equivalence of values is defined by the Abstract Equality Algorithm and its type coercions, and null simply isn't == to anything but undefined.

The more commonly used abstract comparison (e.g. ==) converts the operands to the same Type before making the comparison.
Here, null is a falsy value, but null is not == false
The falsy values null and undefined are not equivalent to anything except themselves:
(null == false); // false
(null == null); // true
(undefined == undefined); // true
(undefined == null); // true
since the other operand is null( which is also a type in javascript ), the abstract comparison of empty string(falsy value) and null doesn't give a truthy value.
I think this will help you.
Comparison Operators
and this too
Truthy and Falsy: When All is Not Equal in JavaScript

Related

Javascript AND OR operators and parentheses

Having issues correctly triggering code in an if and or statement. I want the code in the statement to run when the defholdid var is equal to "cb_SR" AND if ANY of these variables are true: altRighttargets, inRightTargets, safetyRightTargets. I have checked each variable on their own and they all receive the values I expect. Here's the statement:
if (defholdid === "cb_SR" && (altRightTargets === true || inRightTargets === true || safetyRightTargets === true)) {
//code I want to trigger
};
I checked the statement with each individual expression, and I can get the code to trigger, so I think I'm incorrectly writing the statement.
Thanks,
Make sure that the variables you're comparing with true actually hold boolean values, not strings "true" or "false". If they contain these strings, the comparison with true will always be false. In the context of your OR grouping, that variable is effectively ignored.
The strict equality operator === will always be false for values of different types. But even if you change to the loose equality operator ==, true == "true" will be false. When comparing a boolean with another type, the boolean is converted to 0 or 1 first, and then this is compared with the other value (with additional type juggling possible). So true == "1" is true because 1 == "1", but true == "true" is false because 1 == "true" is false. As pointed out in this answer, we have the following cases of comparing a boolean with a string:
true == "true"; //false
true == "1"; //true
false == "false"; //false
false == ""; //true
false == "0"; //true

Eloquent Javascript Ch. 7 - assignment statement with boolean expression

I'm having difficulty understanding the "atDest" variable declaration in this lesson that appears to be taking on two values (both a boolean and an object).
http://eloquentjavascript.net/07_elife.html
actionTypes.eat = function(critter, vector, action) {
var dest = this.checkDestination(action, vector);
var atDest = dest != null && this.grid.get(dest);
if (!atDest || atDest.energy == null)
return false;
critter.energy += atDest.energy;
this.grid.set(dest, null);
return true;
};
Any tips here would help. When I try testing out variables with similar syntax with console.log I've been noticing that the object value overrides the bool. Is this an inherent Javascript trait where a variable can have more than one value?
The boolean operators || and && actually return the value of one of the specified operands.
var a = 5 || false; // 5 is assigned to a
var b = true && 5; // 5 is assigned to b
The logical && returns the first expression if it can be converted to false, otherwise it returns the second expression (or 5 in the example above)
So if dest != null is not false in the following statement
var atDest = dest != null && this.grid.get(dest);
then atDest is assigned the value of this.grid.get(dest).
Here is the documentation you are looking for.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness
http://dorey.github.io/JavaScript-Equality-Table/
The gist is that in JavaScript everything can be interpreted as boolean. The above doc makes it very clear. Values like null, undefined, NaN, 0, "" will be interpreted as falsy. What !atDest really means is basically to check if atDest is not assigned (likely null or undefined).
The next part is also worthy mentioning. atDest.energy == null is a loose equality check (notice the == instead of ===). This check will actually check for both null and undefined. But the difference between atDest.energy == null and !atDest.energy is that atDest.energy == null will not match 0, "", nor NaN.
JavaScript values can be falsy like
false
0 (zero)
"" (empty string)
null
undefined
NaN (a special Number value meaning Not-a-Number!)
or truthy, which is everything else including the empty object {}. Falsy values are equivalent to false in a boolean check and truthy values are equivalent to true in a boolean check.
Now, if you attempt to read a non-existent property on an object you'll get undefined. However if you attempt to read a non defined property off the special value of null or undefined, you will get an error. Something like
Unable to get property 'energy' of undefined or null reference
if you attempt to read atDest.energy when atDest is null or undefined.
So if you want to check if a property is of value xyz on an object that you are not sure is null or undefined, you have to do 2 things
First check if you can actually read the property without error i.e. that the object is not null or undefined.
Then read the property and do the check.
In your example, this
if (!atDest || atDest.energy == null)
does pretty something equivalent. This part
!atDest
evaluates to false if atDest is null or undefined (because both these values are falsy) and short circuits the loop (i.e. doesn't read atDest.energy). In effect what the code attempts to do is this
if (atDest === undefined || atDest === null) {
.... do something ....
else if (atDest.energy == null) {
.... do same something ....
else
.... do something different ....

Undefined or null variable in function

In these example I am ruining a function with conditions;
function validPrice(price)
{
if(price=="" || price==0 || price==null || price==undefined )
{
//do something
}
else
{
// do something different
}
}
var priceNew = $("li#listedProd").attr("price");
validPrice(priceNew);
My question is what are the different in these condition price=="" || price==0 || price==null || price==undefined
Whoever first wrote that code was either
a) Being very defensive against future use.
b) Didn't understand how attr works.
The method attr (or the underlying call of getAttribute will return either
A string value, of the attribute is found
null, if it is not.
Importantly, should there have been a 0 value, it would be a string 0, and thus not caught in the test below -- caught against the price == 0 test because the system would have automatically converted it to a number as part of the == compare.
if(price=="" || price==0 || price==null || price==undefined )
And, due to the way that conversions work internally, those tests don't work as intended. == and === are different. It should be:
if(price === "" || price === 0 || price === null || price === undefined )
All of which can easily be reduced to simply "price" due how how coercion to boolean work:
if (!price)
Or, if you want to catch "0" values
if (!price || +price === 0)
(the +price forces price to be a number, so we catch 0 0.00 and other variations.)
Let's look at your conditional statement term-by-term:
price == ""
This is true if price is the empty string, and false otherwise.
price == 0
This is true if price is the integer 0, the string "0", or the empty string, and false otherwise. You should change this comparison to price === 0 if you want to catch when price is the integer 0.
price == null
This is true if price is passed to your function and is of the type null, and false otherwise.
price == undefined
Note: You should probably make this comparison via price === undefined to see that price is both undefined and has the type undefined.
This is true if price is not passed to your function, or if price is otherwise undefined, and false otherwise.
I would recommend just making the entire conditional statement !price:
function validPrice(price) {
if (!price) {
//do something
}
else {
// do something different
}
};
var priceNew = $("li#listedProd").attr("price");
validPrice(priceNew);
EDIT added definitions
JavaScript has 2 operators that test for equality (and conversely 2 operators that test for inequality.)
A strict equality comparison (e.g., ===) is only true if the operands are of the same type AND if the object is actually the same object, or the primitives have the same value (e.g., 0 === 0, and 'a' === 'a' are both true). *Note there is a slight exception to this rule for NaN (see below)
An abstract equality comparison (e.g. ==) converts the operands to the same Type (if they aren't already) before making a strict equality comparison. If however one of the operands is null or undefined, the comparison is true if and only if the other operand is either null or undefined.
So in short the == equality operator is considered by many to be unsafe. To see the difference checkout http://dorey.github.io/JavaScript-Equality-Table/
For instance '' ==: 0, '', [], false, [[]]
And 0 ==: false, 0, '0', '', [], [[]], [0]
While null ==: null, undefined
And finally undefined ==: null, undefined
It is better to use strict equal === or just test for a falsey value ('', 0, undefined, null, false)
if (!price) { //do something }
Below I have provided more details about strict vs abstract equality comparison
details came from ECMA-262, Edition 5 11.9.1
Summary of strict equality algorithm
1. If typeof(x) is different from typeof(y), return false.
2. If typeof(x) is undefined, return true.
3. If x is null, return true.
4. If typeof(x) is number, then
a. If x is NaN, return false.
b. If y is NaN, return false.
c. If x is the same Number value as y, return true.
d. If x is +0 and y is -0, return true.
e. If x is -0 and y is +0, return true.
f. Return false.
5. If typeof(x) is string, then
a. If x and y are exactly the same sequence of characters (same length and same characters in
corresponding positions), return true.
b. Else, return false.
6. If typeof(x) is boolean, then
a. If x and y are both true or both false, return true.
b. Else, return false.
7. If x and y are the same Object value, return true.
8. Return false.
And ... details came from ECMA-262, Edition 5 11.9.1
Summary of Abstract Equality Algorithm
1. If typeof(x) is the same as typeof(y), then
return the result of performing strict equality comparison algorithm x === y.
2. If x is null and y is undefined, return true.
3. If x is undefined and y is null, return true.
4. If typeof(x) is number and typeof(y) is string,
return the result of the comparison x == Number(y).
5. If typeof(x) is string and typeof(y) is number,
return the result of the comparison Number(x) == y.
6. If typeof(x) is boolean, return the result of the comparison Number(x) == y.
7. If typeof(y) is boolean, return the result of the comparison x == Number(y).
8. If typeof(x) is either string or number and typeof(y) is object,
return the result of the comparison x == [[ToPrimitive]](y).
9. If typeof(x) is object and typeof(y) is either string or number,
return the result of the comparison [[ToPrimitive]](x) == y.
10. Return false.
[[ToPrimitive]] is an internal function call
Bullets 8 and 9 basically mean that objects are converted like object.valueOf().toString() so:
{} == '[Object object]'
{ hi: 'hi'} == '[Object object]'
{ valueOf: function(){ return 0; }} == 0
{ toString: function(){ return 'hi'; }} == 'hi'
{ valueOf: function(){ return 0; }, toString: function(){ return 'hi'; }} == 0
Full ecma-262/5.1/#sec-11.9 spec

how to check falsy with undefined or null?

undefined and null are falsy in javascript but,
var n = null;
if(n===false){
console.log('null');
} else{
console.log('has value');
}
but it returns 'has value' when tried in console, why not 'null' ?
To solve your problem:
You can use not operator(!):
var n = null;
if(!n){ //if n is undefined, null or false
console.log('null');
} else{
console.log('has value');
}
// logs null
To answer your question:
It is considered falsy or truthy for Boolean. So if you use like this:
var n = Boolean(null);
if(n===false){
console.log('null');
} else{
console.log('has value');
}
//you'll be logged null
You can check for falsy values using
var n = null;
if (!n) {
console.log('null');
} else {
console.log('has value');
}
Demo: Fiddle
Or check for truthiness like
var n = null;
if (n) { //true if n is truthy
console.log('has value');
} else {
console.log('null');
}
Demo: Fiddle
A value being "falsy" means that the result of converting it to a Boolean is false:
Boolean(null) // false
Boolean(undefined) // false
// but
Boolean("0") // true
This is very different from comparing it against a Boolean:
null == false // not equal, null == true is not equal either
undefined == false // not equal, undefined == true is not equal either
// but
"0" == true // not equal, however, `"0" == false` is equal
Since you are using strict comparison, the case is even simpler: the strict equality comparison operator returns false if operands are not of the same data type. null is of type Null and false is of type Boolean.
But even if you used loose comparison, the abstract equality algorithm defines that only null and undefined are equal to each other.
Depending on what exactly you want to test for, you have a couple of options:
if (!value) // true for all falsy values
if (value == null) // true for null and undefined
if (value === null) // true for null
In general you should always prefer strict comparison because JS' type conversion rules can be surprising. One of the exceptions is comparing a value against null, since loose comparison also catches undefined.
=== checks for identity - the exact same type and value. So null !== false firstly because they are not the same type, thus will not match when using ===.
If you just want to check for any falsey value, then check with:
if (!n)
If you want to specifically check for null, then check for null like this:
if (n === null)

Short-circuiting an empty array in JS has an unexpected outcome: `[] || true == []`

In my code I assumed the following || short-circuiting was safe:
var $holidayExpandBarOrOpeningHours =
$(".expandBar + .holidayHours_c").prev() || $(".openingHours");
But to my surprise if we short-circuit an empty array with a true statement an empty array is still returned. I will demonstrate with some console code below and my question is why [] || true evaluates to [].
false || "expected"
"expected"
false == []
true
[] || "expected"
[]
typeof([])
"object"
({}) || "expected"
Object {}
({}) == false
false
{} == false
SyntaxError: Unexpected token ==
Part of me thinks that it is because an array is an object which evaluates to true, however if that was the case than based on ({}) == true one would expect [] == true.
Last thing I would like to note is the outcome is the same when using use 'strict' mode.
When converted to a boolean value, [] is true.
> !![]
true
> ![]
false
When converted to a number, [] is 0. That's why comparing it with false returns true: when comparing two values of different types, JavaScript first converts both to numbers and then compares the numbers.
> +[]
0
> +false
0
> +[] == +false
true
This is because || and use == different rules for the conversion.
The logical-or uses ToBoolean while the equality equals uses ToNumber/ToPrimitive.
From 11.11 Binary Logical Operators:
3) If ToBoolean(lval) is true, return lval.
Since ToBoolean([]) is true, [] || x results in []. This is also why if([]) { /* this runs */ }: arrays in JavaScript are "truthy" values.
From 11.9.3 The Abstract Equality Comparison Algorithm:
7) If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
9) [..then] If Type(x) is Object and Type(y) is either String or Number,
return the result of the comparison ToPrimitive(x) == y.
5) [..then] If Type(x) is String and Type(y) is Number,
return the result of the comparison ToNumber(x) == y.
The logic applied to [] == true is ToNumber(ToPrimitive([])) == ToNumber(true).
And the conversion values:
ToBoolean([]) is true
ToNumber(true) is 1
ToPrimitive([]) is an empty string (from DefaultValue/toString)
So:
ToNumber(ToPrimitive([])) == ToNumber(true)
ToNumber("") == 1
0 == 1
false
(Which is a long way to say what John Kugelman said.)
Also, ({}) == true is normally false and follows the same conversions as above.
Under a default environment, ToPrimtive({}) returns a non-empty string (i.e. "[object Object]" as per Object.prototype.toString). This string will evaluate to NaN after ToNumber such that NaN == 1; or false.
See Why an empty Array type-converts to zero? +[] for more details on the ToPrimitive conversion.
An empty array is an object; objects coerced to booleans are true. So
({}) || true; // -> {}
[] || true; // -> []
"" || true; // -> true (empty strings are coerced to false)
Sidenote - the parentheses around {} are required to avoid parsing it as a block.

Categories