What causes isNaN to malfunction? [duplicate] - javascript

This question already has answers here:
Validate decimal numbers in JavaScript - IsNumeric()
(52 answers)
Closed 9 years ago.
I'm simply trying to evaluate if an input is a number, and figured isNaN would be the best way to go. However, this causes unreliable results. For instance, using the following method:
function isNumerical(value) {
var isNum = !isNaN(value);
return isNum ? "<mark>numerical</mark>" : "not numerical";
}
on these values:
isNumerical(123)); // => numerical
isNumerical("123")); // => numerical
isNumerical(null)); // => numerical
isNumerical(false)); // => numerical
isNumerical(true)); // => numerical
isNumerical()); // => not numerical
shown in this fiddle: http://jsfiddle.net/4nm7r/1
Why doesn't isNaN always work for me?

isNaN returns true if the value passed is not a number(NaN)(or if it cannot be converted to a number, so, null, true and false will be converted to 0), otherwise it returns false. In your case, you have to remove the ! before the function call!
It is very easy to understand the behaviour of your script. isNaN simply checks if a value can be converted to an int. To do this, you have just to multiply or divide it by 1, or subtract or add 0. In your case, if you do, inside your function, alert(value * 1); you will see that all those passed values will be replaced by a number(0, 1, 123) except for undefined, whose numerical value is NaN.
You can't compare any value to NaN because it will never return false(even NaN === NaN), I think that's because NaN is dynamically generated... But I'm not sure.
Anyway you can fix your code by simply doing this:
function isNumerical(value) {
var isNum = !isNaN(value / 1); //this will force the conversion to NaN or a number
return isNum ? "<mark>numerical</mark>" : "not numerical";
}

Your ternary statement is backward, if !isNaN() returns true you want to say "numerical"
return isNum ? "not numerical" : "<mark>numerical</mark>";
should be:
return isNum ? "<mark>numerical</mark>" : "not numerical";
See updated fiddle:
http://jsfiddle.net/4nm7r/1/

Now that you already fixed the reversed logic pointed out on other answers, use parseFloat to get rid of the false positives for true, false and null:
var isNum = !isNaN(parseFloat(value));
Just keep in mind the following kinds of outputs from parseFloat:
parseFloat("200$"); // 200
parseFloat("200,100"); // 200
parseFloat("200 foo"); // 200
parseFloat("$200"); // NaN
(i.e, if the string starts with a number, parseFloat will extract the first numeric part it can find)

I suggest you use additional checks:
function isNumerical(value) {
var isNum = !isNaN(value) && value !== null && value !== undefined;
return isNum ? "<mark>numerical</mark>" : "not numerical";
}
If you would like treat strings like 123 like not numerical than you should add one more check:
var isNum = !isNaN(value) && value !== null && value !== undefined && (typeof value === 'number');

Related

Check if String can be converted to number

I created the following Typescript extension to convert a string to Number:
declare global {
interface String {
toNumber(): number | null;
}
}
String.prototype.toNumber = function(this: string) {
return parseFloat(this);
}
When it is not possible to parse the string to number either because it is invalid, null, undefined, etc I would always like to return null.
How can I do this?
I am assuming you already understand the differences between parseFloat / Number as conversion mechanisms.
Effectively all you need to do is check if the output is NaN. You can do this by:
String.prototype.toNumber = function(this: string) {
const num = parseFloat(this);
return Number.isNaN(num) ? null : num;
}
If you want to return either a non-zero valid number (well, note that NaN is a number, but I think I know what you mean), then check for what you don't want before returning:
Object.defineProperty(String.prototype, "toNumber", {
value: function(str) {
let num = Number(str);
return num === 0 || isNaN(num) ? null : num;
}
});
(Defining properties directly on the prototype is a bad habit and can lead to weird behavior; using .defineProperty gives you a property that is not enumerable.)
Oh, and that's JavaScript, obviously, not Typescript.
A simple answer would be to use return Number(this) || null;
The Number function will convert to a number or NaN, NaN || null will return null (because NaN is falsey).
Updated added testing for zero condition, which with the above code would have also returned null. If that is not what you want, this code will allow zero to return. (Note that this can be done many different ways!):
const parsedValue = Number(this);
return parsedValue === 0 ? parsedValue : parsedValue || null;
Updated to use the parseFloat function, example of early exit for string of '0'. Very similar to the previous updated example.
if (this === '0') {
return 0;
}
return parseFloat(this) || null;

How to check 2 different types of things using ===?

I want to check whether the value in an input box is equal to a variable. When I use ===, it returns false but when I use ==, it returns true, provided both are equal.
<input id="g1"></input> <button id="b" onclick="myFunction()">Try</button>
function myFunction() {
var d1;
d1 = Math.floor(Math.random()*100)
if( document.getElementById("g1").value == d1) {
document.getElementById("d").innerHTML = "Correct";
}
This happens because JavaScript == can compare numeric strings to numbers whereas === does not.
Similarly the "value" property your using returns a string that you're comparing to an integer. You'll need to use parseInt to convert the value first.
parseInt(document.getElementById("g1").value) === d1
A few things to consider with parseInt:
parseInt returns NaN when you try to convert non-number strings (i.e. converting 'bogus' returns NaN.
It will convert decimals into integers by dropping the decimals. So parseInt('2.1') == 2 // => true.
Honestly, given your use case, it's appropriate to use ==, but I'd add a comment explaining why it's being used.
=== means both value has to be equals but have same type of data in it aswell where == means they only needs to be equal. so for example if d1 is a string holding value 2 and g1 is an integer also holding value 2 using === would not work and will return false as both data is different even though they have same syntax.
<input id="g1"></input> <button id="b" onclick="myFunction()">Try</button>
function myFunction() {
var d1 = 0;
d1 = Math.floor(Math.random()*100)
if( paseint(document.getElementById("g1").value) === d1) {
document.getElementById("d").innerHTML = "Correct";
}
== is the equality operator
=== is an identity operator
For example true==1 is true because true is converted to 1 and then it's compared. However, true===1 is false. This is because it does not do type coercion.
That aside, in your case I think you want to try casting your value to an integer and then compare.
var string5 = '5'
var numb5 = 5
if (string5 == numb5) will return true
if (string5 === numb5) will return false
second variant also compares type, because string is not same type as number it is false.

isFinite of space giving true value

I am trying to validate a price field. I was trying this:
var productId = document.getElementById("productId");
var productName = document.getElementById("productName");
var productPrice = document.getElementById("price");
alert(isFinite(productPrice.value));
if(isNaN(productPrice.value)||!isFinite(productPrice.value)){
error = document.getElementById("priceError");
error.innerHTML = "Please enter correct value";
productPrice.style.border="thin solid red";
}else{
error = document.getElementById("priceError");
error.innerHTML = "";
}
The line alert is giving me true when the input is space/ multiple spaces only.
This is my HTML page.
<td>Price</td>
<td><input type = "text" id = "price" size = "14"/></td>
Thanks
Why this happens i cant say, but this code should solve the problem
isFinite(parseFloat(" ")) // false
// because -->
parseFloat(" "); // => result NaN
// tested in Chrome 27+ on Win7
in the MDN refernce of isNaN here
it says
isNaN(" "); // false: a string with spaces is converted to 0 which is not NaN
Update:
in the Reference of isFinite found Here it states that isFinite only returns false if the argument is:
NaN
positive infinity, (Number.POSITIVE_INFINITY)
negative infinity (Number.NEGATIVE_INFINITY)
In any other Case it returns true. (like Paul S mentioned)
Now i Think i got all loose ends, and in that course learned something. :)
with window.isFinite, you must be aware of the issues that window.isNaN suffers from when coercing types.
window.IsNaN Summary
Determines whether a value is NaN or not. Be careful, this function is
broken. You may be interested in ECMAScript 6 Number.isNaN.
Examples
isNaN(NaN); // true
isNaN(undefined); // true
isNaN({}); // true
isNaN(true); // false
isNaN(null); // false
isNaN(37); // false
// strings
isNaN("37"); // false: "37" is converted to the number 37 which is not NaN
isNaN("37.37"); // false: "37.37" is converted to the number 37.37 which is not NaN
isNaN(""); // false: the empty string is converted to 0 which is not NaN
isNaN(" "); // false: a string with spaces is converted to 0 which is not NaN
// This is a false positive and the reason why isNaN is not entirely reliable
isNaN("blabla") // true: "blabla" is converted to a number. Parsing this as a number fails and returns NaN
In ECMAScript 6 there are new methods Number.isNaN and Number.isFinite that address these issues. (of course these are not available in many browsers)
Number.isFinite is equivalent to
function isFinite(number) {
return typeof number === "number" && window.isFinite(number);
}
So as a solution, you would need to consider something like this (cross-browser).
Note: this solution will still allow you to enter hexadecimal or scientific notations, "0xA", "1e10"
Javascript
function isFinite(number) {
return typeof number === "number" && window.isFinite(number);
}
function trim(string) {
return string.replace(/^\s+|\s+$/g, "");
}
var price = document.getElementById("price");
price.onchange = function (e) {
var evt = e || window.event,
target = evt.target || evt.srcElement,
value = trim(target.value) || "NaN",
number = +value;
console.log("number:", number);
console.log("isFinite:", isFinite(number));
}
On jsfiddle
You could do it using reqular expression.
Try this.
function validatePrice() {
var el = document.getElementById('price');
if (
el.value.length < 14 &&
/^ *\+?\d+ *$/.test( el.value )
)
{
return true;
}
return false;
}
This function checks if the input is positive integer. I didnt know if you want floated values also.
If you do, switch the regex to this /^ *+?\d+((.|,)\d+)? *$/

Why using this method to return a function or value?

I'm just wondering why should I use this method to return a function :
clusters.prototype.get_local_storage_data = function(data_key) {
return +(this.localStorage.getItem(data_key) || 1);
};
What does the +() do there and why using that ? Is there a better way of returning the function or 1 if what the function gets is null ?
Using the + before a value forces that value to become a number. In the case above, the data key will be converted to a number (if it's found), or the number 1 will be returned. Either way, the result will be converted to a number.
+null; // 0
+"3.14"; // 3.14
+1; // 1
It's just ensuring that no matter what the output is, you will be returning a number.
The + is there to cast the result to a number -
typeof +"123" // "number"
The way it's implemented looks just fine, and doesn't need to be changed.
The + is just making sure the return value is a number or else 1 would be true and not the number one. It's a shortcut for:
Number( expression )

Comparing NaN values for equality in Javascript

I need to compare two numeric values for equality in Javascript. The values may be NaN as well.
I've come up with this code:
if (val1 == val2 || isNaN(val1) && isNaN(val2)) ...
which is working fine, but it looks bloated to me. I would like to make it more concise. Any ideas?
if(val1 == val2 || (isNaN(val1) && isNaN(val2)))
Nothing to improve. Just add the parentheses to make it clear to everyone.
Avoid isNaN. Its behaviour is misleading:
isNaN(undefined) // true
_.isNaN (from Underscore.js) is an elegant function which behaves as expected:
// Is the given value `NaN`?
//
// `NaN` is the only value for which `===` is not reflexive.
_.isNaN = function(obj) {
return obj !== obj;
};
_.isNaN(undefined) // false
_.isNaN(0/0) // true
Try using Object.is(), it determines whether two values are the same value. Two values are the same if one of the following holds:
both undefined
both null
both true or both false
both strings of the same length with the same characters in the same order
both the same object
both numbers and
both +0
both -0
both NaN
or both non-zero and both not NaN and both have the same value
e.g. Object.is(NaN, NaN) => true
Refer to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
if ( val1 === val2 )
If either one or both are NaN it will evaluate to false.
Also, NaN !== NaN
As long as you know these two variables are numeric, you can try:
if (val1 + '' == val2 + '')
It turns the two values into strings. A funny answer, but it should work. :)
NaN is never equal to itself no matter the comparison method, so the only more concise solution for your problem that I can think of would be to create a function call with a descriptive name for doing this rather special comparison and use that comparison function in your code instead.
That would also have the advantage of localizing changes to the algorithm the day you decide that undefined should be equal to undefined too.
And what's about the function Number.isNaN() ? I believe this must be used whenever is possible.
> NaN === NaN
false
> Number.isNaN
ƒ isNaN() { [native code] }
> Number.isNaN() === Number.isNaN()
true
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN
For Numeric cases the solution is fine but to extend it to work for other data-types as well my suggestion would be as follows:
if(val1 === val2 || (val1 !== val1 && val2 !== val2))
Reason being global isNaN is erroneous. It will give you wrong results in scenarios like
isNaN(undefined); // true
isNaN({}); // true
isNaN("lorem ipsum"); // true
I have posted a comprehensive answer here which covers the NaN comparison for equality as well.
How to test if a JavaScript variable is NaN
Why not an if statement like this?
if (isNaN(x) == true){
alert("This is not a number.");
}
Equality comparison with NaN always results in False.
We can go for the javascript function isNaN() for checking equality with NaN.
Example:
1. isNaN(123) //false
2. var array = [3, NaN];
for(var i = 0 ; i< array.length; i++){
if(isNaN(array[i])){
console.log("True ---- Values of " + i);
} else {
console.log("false ---- Values of " + i);
}
}
Results:
false ---- Values of 0
True ---- Values of 1
Found another way using Array.prototype.includes MDN link. Apparently, [NaN].includes(NaN) returns true for NaN.
function IsActuallyNaN(obj) {
return [obj].includes(NaN);
}
Or we can go with davidchambers' solution which is much simpler.
function IsActuallyNaN2(obj) {
return obj !== obj;
}

Categories

Resources