In which cases should `==` be used over `localeCompare` and viceversa, in Javascript? - javascript

What are the pros and cons of each of them when compared to each other?
In which cases should == be used over localeCompare and viceversa, in Javascript?

They are not at all the same!
Non-strict comparison compares strings to see if they are the same (only included strings as that's what localeCompare works on, types are irrelevant).
"test" == "test" // true
localCompare is a lot more than that, it returns a number indicating whether a reference string comes before or after or is the same as the given string in sort order, and in the specified language.
'a'.localeCompare('c') // returns a negative value, i.e. -1 etc, a comes before c
'a'.localeCompare('a') // returns 0, they are the same
'c'.localeCompare('a') // returns a positinve value, i.e. 1 etc, c comes after a
note that the sort order used is entirely implementation dependent, but in most browsers it will be alphabetical
or language specific
'ä'.localeCompare('z', 'sv')); // a positive value: in Swedish, ä sorts after z
As it return a negative integer, zero or a positive integer, it's useful in functions such as sort() which expects the return of the sorting callback to be just that, a negative integer, zero or a positive integer.
MDN

localeCompare is not the same as ==. When you compare two variables using ==, you check whether or not the variables have the same content. This will return a boolean (true/false). However, localeCompare does not return a boolean but an int instead.
You will receive a 0 when the two variables are the same, but you will however receive either 1 or -1 if your variables are not the same. The value is based on whether the first variable comes before or after the second variable in sort order.
So I myself would use == when I'm purely validating if two variables are the same, but localeCompare can become handy when you want to see what variable comes first in sort order, however it can be used to compare two variables to see if they are the same.
string a = "hello";
string b = "world";
a == b // returns false
a.localeCompare(b); // returns -1
To answer your question slightly, these are the characteristics / pro's and cons of using either of the examples given:
Using ==
Returns a boolean instead of a string/integer/...
Easier to read by most people
Using localeCompare
Returns an integer (-1, 0 or +1)
Can be used to sort variables

localeCompare doesn't just check for equality in value. It also compares the values when they're different, and returns a 1 / -1 depending on which value is higher. It's return value is in no way similar to a equality check.
localeCompare can be used for sorting strings, as the return value is different from == when the 2 values aren't the same, == can only be used for determining equality (in value, not type).
For example:
"2".localeCompare(2) // 0
"2".localeCompare(1) // 1
"2".localeCompare(3) // -1
"2" == 2 // true
"2" == 1 // false
"2" == 3 // false
"b".localeCompare("b") // 0
"b".localeCompare("a") // 1
"b".localeCompare("c") // -1
"b" == "b" // true
"b" == "a" // false
"b" == "c" // false
The return value from localeCompare happens to be exactly what Array.prototype.sort() expects to be returned from it's handler.

localeCompare is very useful to implement a sorting (ascending or descending) function:
myLabelsArray.sort(function(a, b){
return a.label.localeCompare(b.label);
});
Indeed, localeCompare returns -1, 0 (if equals) or 1 (based on locale language rules), allowing to get a sorting.
It would take more lines to implement it with == + <, explicitly returning integers.

Related

EloquentJavaScript: !Number.isNaN() what is the purpose? [duplicate]

Soooooo isNaN is apparently broken in JavaScript, with things like:
isNaN('')
isNaN(' ')
isNaN(true)
isNaN(false)
isNaN([0])
Returning false, when they appear to all be... Not a Number...
In ECMAScript 6, the draft includes a new Number.isNaN but it looks like (imo) that this is also broken...
I would expect
Number.isNaN('RAWRRR')
To return true, since it's a string, and cannot be converted to a number... However...
It seems that things that I would consider... not a number, are indeed, not, not a number...
http://people.mozilla.org/~jorendorff/es6-draft.html#sec-isfinite-number
The examples on MDN say:
Number.isNaN("blabla"); // e.g. this would have been true with isNaN
I don't understand how this is "More robust version of the original global isNaN." when I cannot check to see if things are not a number.
This would mean we're still subjected to doing actual type checking as well as checking isNaN... which seems silly...
http://people.mozilla.org/~jorendorff/es6-draft.html#sec-isnan-number
The ES3 draft here basically says, everything is always false, except with its Number.NaN
Does anyone else find this is broken or am I just not understanding the point of isNaN?
isNaN() and Number.isNaN() both test if a value is (or, in the case of isNaN(), can be converted to a number-type value that represents) the NaN value. In other words, "NaN" does not simply mean "this value is not a number", it specifically means "this value is a numeric Not-a-Number value according to IEEE-754".
The reason all your tests above return false is because all of the given values can be converted to a numeric value that is not NaN:
Number('') // 0
Number(' ') // 0
Number(true) // 1
Number(false) // 0
Number([0]) // 0
The reason isNaN() is "broken" is because, ostensibly, type conversions aren't supposed to happen when testing values. That is the issue Number.isNaN() is designed to address. In particular, Number.isNaN() will only attempt to compare a value to NaN if the value is a number-type value. Any other type will return false, even if they are literally "not a number", because the type of the value NaN is number. See the respective MDN docs for isNaN() and Number.isNaN().
If you simply want to determine whether or not a value is of the number type, even if that value is NaN, use typeof instead:
typeof 'RAWRRR' === 'number' // false
No, the original isNaN is broken. You are not understanding the point of isNaN.
The purpose of both of these functions is to determine whether or not something has the value NaN. This is provided because something === NaN will always be false and therefore can't be used to test this.
(side note: something !== something is actually a reliable, although counter-intuitive, test for NaN)
The reason isNaN is broken is that it can return true in cases when a value is not actually NaN. This is because it first coerces the value to a number.
So
isNaN("hello")
is true, even though "hello" is not NaN.
If you want to check whether a value actually is a finite number, you can use:
Number.isFinite(value)
If you want to test whether a value is a finite number or a string representation of one, you can use:
Number.isFinite(value) || (Number.isFinite(Number(value)) && typeof value === 'string')
As mentioned in a comment isNaN() and Number.isNaN() both check that the value you pass in is not equal to the value NaN. The key here is that NaN is an actual value and not an evaluated result e.g. "blabla" is a String and the value is "blabla" which means it is not the value "NaN".
A plausible solution would be doing something like:
Number.isNaN(Number("blabla")); //returns true.
The key difference between the two is that the global isNaN(x) function performs a conversion of the parameter x to a number. So
isNaN("blabla") === true
because Number("blabla") results in NaN
There are two definitions of "not a number" here and that's perhaps where the confusion lies. Number.isNaN(x) only returns true for the IEEE 754 floating point specification's definition of Not a Number, for example:
Number.isNaN(Math.sqrt(-1))
as opposed to determining whether the object being passed in is of numeric type or not. Some ways of doing that are:
typeof x === "number"
x === +x
Object.prototype.toString.call(x) === "[object Number]"
Basically, window.isNaN performs a type conversion to a number, then checks if it is NaN. Whereas, Number.isNaN doesn't try to convert its argument to a number. So basically, you can think of window.isNaN, and Number.isNaN as working like so.
window.isNaN = function(n){
return Number(n) !== Number(n);
}
window.Number.isNaN = function(n){
return n !== n;
}
Please note that you don't need actually to use the window. to call isNaN or Number.isNaN. Rather, I am just using it to provide a better distinction between the two similarly-named methods to try to cut down on confusion.
~ Happy Coding!
The following works because NaN is the only value in javascript which is not equal to itself.
Number.isNaN = Number.isNaN || function(value) {
return value !== value;
}
Per, MDN, it (NaN) is the returned value when Math functions fail and as such it is a specific value. Perhaps a better name would have been, MathFunctionFailed.
To determine if something is a number requires parsing which fails nicely over a broad range of non numeric inputs, successfully detecting numbers and strings representing numbers, hence:
function isNumber(v) {return Number.isNaN(parseFloat(v)); }
1. Number.isNaN
alert(Number.isNaN('Hello')); // false
Shouldn't it return true because Hello is a string and its Not A Number right ? But Lets know why it returns false.
MDN docs says :
true if the given value is NaN and its type is Number; otherwise,
false.
Yes Hello value is NaN but the type is string , you can check the type as follows:
alert(typeof `Hello`); // string
Usage:
Use when you want to check the value is both NaN and type is number.
2. isNaN
alert(isNaN('Hello')); // true
MDN docs says:
true if the given value is NaN; otherwise, false.
Usage:
Use when you want to check value is just NaN.
3. jQuery.isNumeric()
Jquery Docs Says :
Determines whether its argument represents a JavaScript number.
alert($.isNumeric('Hello')); // false
alert($.isNumeric(3)); //true
Usage:
Use when you want to check value is a number or can be converted to a number.
Reference
I use a simple workaround to check Number.isNaN():
let value = 'test';
Number.isNaN(-value); // true
value = 42;
Number.isNaN(-value); // false
js trying to convert the value to the negative Number, if the conversion is failed - we have NaN.
Simple, isn't it?
Moreover, online benchmark tests say Number.isNaN is lighter than isNaN.
Number.isNaN(x) checks if x is directly evaluated to NaN or not.
RAWR is not the same as NaN. Think of NaN as an entity to represent the result of some mathematical calculation where the computer does not know how to represent the number.
A mathematical operation is not going to yield a non-numeric result, hence the typeof NaN is number.
The string RAWR had undergone no mathematical operation to yield NaN. However, if you were to call Number.isNaN(+'RAWR'), it would result in NaN since the unary + operator is trying to convert 'RAWR' to a number.
On the other hand, isNaN(y) tells whether y can be converted to a number or not. If isNaN(y) is false, y can be converted to a number. But if isNaN(y) is true, y can not be converted to a number.
So a good rule of thumb is:
Do I want to check if x can be successfully converted to a number? Use isNaN(x) == false in that case. Unsuccessful conversion results in NaN.
Do I want to check if x is evaluated to NaN? Use Number.isNaN(x) == true for that.
#phill, as stated in other responses, neither is broken.
Number.isNaN work on a number or instance of Number, so even Number.isNaN(new Date(NaN)) is false.
isNaN, on the other hand, is generic and tries to convert its parameter to a number before checking it.
If you want to determine if a value is (or contains) NaN, you can use this function:
function valueIsNaN(value) {
// eslint-disable-next-line no-self-compare
return value !== value || typeof value == 'object' && Number.isNaN(value.valueOf());
}

A javascript statement that I haven't seen before

I am inspecting some Javascript code written in UnderscoreJS. In this, there are quite a few instances of JS code being written like this:
if(length === +length){ //do something}
or
if(length !== +length){ //do something }
What exactly does this compute to? I have never seen this before.
if (length === +length)
It makes sure that the length is actually a numeric value.
Two things to understand here,
The Strict equality operator, will evaluate to true only when the objects are the same. In JavaScript, the numbers and strings are immutables. So, when you compare two numbers, the Number values will be compared.
Unary + operator will try to get the numeric value of any object. If the object is already of type Number, it will not make any changes and return the object as it is.
In this case, if length is actually a number in string format, lets say "1", the expression
"1" == +"1"
will evaluate to be true, because "1" is coerced to numeric 1 internally and compared. But
"1" === +"1"
which will be transformed to
"1" === 1
and that will not undergo coercion and since the types are different, === will evaluate to false. And if length is of any other type, === will straight away return false, as the right hand side is a number.
You can think of this check as a shorthand version of this
if (Object.prototype.toString.call(length) === "[object Number]")
It is a way of testing whether a value is numeric. See this for example:
> length="string"
> length === +length
false
> length=2
> length === +length
true
The unary + converts the variable length to the Number type, so if it was already numeric then the identity will be satisfied.
The use of the identity operator === rather than the equality operator == is important here, as it does a strict comparison of both the value and the type of the operands.
Perhaps a more explicit (but slightly longer to write) way of performing the same test would be to use:
typeof length === "number"

Why eval("475957E-8905") == "475957E-8905" is true?

I made a program with nodeJs which generate code such as
eval("XXXXXX") == "XXXXXX"
It's working pretty well, but at a moment he gave me this :
eval("475957E-8905") == "475957E-8905"
I tested it with Firebug, and the result is true
.But I don't really understand why.
Of course, eval("475957E-8905") return 0
but why 0 == "475957E-8905" ?
There are two pieces to this puzzle: floating-point numbers and type-insensitive comparison using ==.
First, 475957E-8905 evaluates as the floating point number 475957 * 10 ^ -8905, which is incredibly small; in floating-point terms, it's the same as 0 due to the precision limitations of javascript. So, eval("475957E-8905") returns 0.
Now, for the second piece of the puzzle.
The == means that the types don't have to match, so nodejs (like any JavaScript engine) tries to convert one of them so it can compare them.
Since eval("475957E-8905") returned 0, it tries to convert "475957E-8905" to an integer as well. As we have seen, that is also 0. Thus, the comparison is 0 == 0, which is true.
Note that the same thing happens if you do eval("3") == "3" or eval("3") == 3 -- in each case, the strings are converted to numbers and compared.
Avoiding this problem
You can force a type-sensitive comparison like this:
eval("475957E-8905") === "475957E-8905"
which returns false, because the === tells the javascript engine to return true only if the types and the values both match.
Javascript has to convert your string, "475957E-8905", to a number in order to compare them. When it does that, it converts "475957E-8905" to 0 as well. So, 0 == 0;
As you can see:
"475957E-8905" == 0
Is true. Basically you eval statement "475957E-8905" into a number, and then the other "475957E-8905" is being converted to a number for comparison. In the end, the exact same conversion process has happened to both of them and they are both 0.
use === to compare the type as well, for further information:
JavaScript has both strict and
type-converting equality comparison.
For strict equality the objects being
compared must have the same type and:
Two strings are strictly equal when they have the same sequence of
characters, same length, and same
characters in corresponding positions.
Two numbers are strictly equal when they are numerically equal (have
the same number value). NaN is not
equal to anything, including NaN.
Positive and negative zeros are equal
to one another.
Two Boolean operands are strictly equal if both are true or
both are false.
Two objects are strictly equal if they refer to the same Object.
Null and Undefined types are == (but not ===). [I.e. Null==Undefined (but not Null===Undefined)]
check this documentation

Javascript equality triple equals but what about greater than and less than?

I was explaining to a colleague that you should use === and !== (and >== and <== of course) when comparing variables in JavaScript so that it doesn't coerce the arguments and get all froopy and confusing but they asked me a two part question that I did not know the answer to and thought I would ask the experts here, specifically it is:
What about > and < - when they compare do they also coerce the arguments or not - why isn't there some sort of >> and << operator (probably need to be some other syntax as I would guess they would be bit shift operators if it is going along the whole C style but you get the gist)?
So I can write a test to find the answer to the first part, which I did, here it is:
// Demo the difference between == and ===
alert(5 == "5");
alert(5 === "5");
// Check out what happens with >
alert(5 > "4");
alert(5 > 4);
and it returned:
true
false
true
true
so it does look like the > is doing the coercion since > "4" and > 4 return the same result. so how about the second part...
Is there some sort of operator for > and < that do not coerce the type (or how can I change my test to perform the test safely)?
No, there's no need for such operators. The type checking done for those relational operators is different than for equality and inequality. (edit — perhaps it's a little strong to say that there's "no need"; that's true only because JavaScript deems it so :-)
Specifically, the > and < and >= and <= operators all operate either on two numeric values, or two strings, preferring numeric values. That is, if one value is a number, then the other is treated as a number. If a non-number can't be cleanly converted to a number (that is, if it ends up as NaN), then the result of the comparison is undefined. (That's a little problematic, because undefined will look like false in the context of an if statement.)
If both values are strings, then a collating-order string comparison is performed instead.
If you think about it, these comparisons don't make any sense for object instances; what does it mean for an object to be "greater than" another? I suppose, perhaps, that this means that if you're finding yourself with values of variant types being compared like this, and that's causing problems, then yes you have to detect the situation yourself. It seems to me that it would be good to work upstream and think about whether there's something fishy about the code that's leading to such a situation.
Is there some sort of operator for > and < that do not coerce the type
No.
how can I change my test to perform the test safely
You would have to explicitly test the types:
typeof a === typeof b && a > b
I referenced Flanagan's JavaScript: The Definitive Guide (5th Ed.) and there does not seem to be non-coercive comparison operators.
You are right in saying the << and >> are indeed bitwise operators so that wouldn't work.
I would suggest you deliberately coerce the values youself:
var num_as_string = '4';
var num = +num_as_string;
if (5 > num) { ... }
12 > '100' // false
'12' > 100 // false
'12' > '100' // true
As others mentioned, if one is a number the other is casted to a number. Same rule applies to these cases as well:
null > 0 // false
null < 0 // false
null >= 0 // true
However, there might be cases that you would need null >= 0 to give false (or any of the number string comparison cases above), therefore it is indeed a need to have strict comparison >== or <==.
For example, I am writing a compareFunction for the Array.prototype.sort() and an expression like x>=0 would treat null values like 0's and put them together, whereas I want to put them elsewhere. I have to write extra logic for those cases.
Javascript says deal with it on your own (in practice).

Javascript if-statement vs. comparsion

Is it true that in if-statement JavaScript wrap the condition into a Boolean?
if(x) => if(Boolean(x))
Is it true that in comparison JavaScript wrap the compare elements into a Number?
a == b => Number(a) == Number(b)
Yes, and No.
For the first part, yes, that is essentially what the javascript does.
But for the latter, no. Not everything in JavaScript can be converted to a number. For example:
Number('abc') // => NaN
And Not-A-Numbers are not equal:
NaN == NaN // => false
So something like this:
Number('abc') == Number('abc') // => false!
But that's actually true with equality comparison.
'abc' == 'abc' // => true
As a side note, it's probably better to use === in JavaScript, which also checks the type of the values being compared:
0 == '0' // => true
0 === '0' // => false, because integer is not a string
More details about === can be read over here.
Yes, that's true, x is evaluated in a boolean context in this situation, so the equivalent of Boolean(x) is applied.
No, that's not true. It only looks that way because the coercitive equality operator == tries to convert a and b to the same type. Number() is only applied if either a or b is already a Number. For instance:
>>> 0x2A == 42
true // both 'a' and 'b' are numbers.
>>> "0x2A" == 42
true // 'a' is a string whose number coercion is equal to 'b'.
>>> "0x2A" == "42"
false // 'a' and 'b' are different strings.
Is it true that in if-statement JavaScript wrap the condition into a Boolean?
Usually yes.
Is it true that in comparison JavaScript wrap the compare elements into a Number?
Absolutely no.
Explanation
From JavaScript Language Specifications.
The if statement is defined at § 12.5 as:
if ( Expression ) Statement else Statement
It says that the Expression will be evaluated, converted with GetValue() and then tested after the ToBoolean() conversion.
Then the first assertion is true (but see later), the condition for the if statement is evaluated like is passed as parameter to the Boolean function. Please recall how JavaScript handles type conversion to boolean (§ 9.2):
undefined and null values are converted to false.
numbers are converted to false if ±0 or NaN otherwise they're converted to true.
strings are converted to false if empty otherwise always to true regardless their content.
objects are always converted to true.
Because of the call to GetValue() strictly speaking this assertion is not always true, take a look to § 8.7.1 where the standard describes how GetValue() works, here can happen some magic conversion before ToBoolean() is called.
The == operator is defined as in § 11.9.3.
As you can see it doesn't specify that operands must be (or will be treated as) numbers, the behavior of the operator is different and regulated by a series of rules based on the type of the operands. Then your second assertion is false. The case they're numbers (or one of them is a number) is just a special case in the algorithm, please note that at point 4 of the algorithm it says that if one of them is a number and the other one is a string then it'll be converted with ToNumber(), only in this case (with all the implications that this conversion has).
It's intuitive if you think that you can compare functions, strings or numbers, not every type can be converted to a numeric value.

Categories

Resources