I'm a complete beginner to coding. I was learning javascript and came across a problem which I couldn't figure out. Hope someone could explain this to me (much appreciated).
The function isNaN is supposed to check whether a variable let's say is not a number. The problem is when you code like this,
var b = "44" //this is a string
if ( isNaN(b) ) {
alert("b is not a number"); // does not give me the alert
}
//But if you put an else statement to this
else {
alert("b is a number"); //alerts as b is a number when it's a string
}
I would really appreciate if someone could explain why this particular piece of code alerts as "b is a number" when it's a string. Many thanks.
Even though isNaN is called "is Not a Number", it does not check whether a value is "not a number". It specifically checks if a value is NaN.
NaN is a special value. According to MDN: "It is the returned value when Math functions fail (Math.sqrt(-1)) or when a function trying to parse a number fails (parseInt("blabla")).
Because B is not NaN, the else clause will fire and "B is a number" will be alerted.
Checking for numbers
If you want to know whether a value is a number, you can use typeof:
var b = "44";
if (typeof b !== "number") {
alert("b is not a number");
} else {
alert("b is a number");
}
Global.isNaN converts the argument to a number, then checks wether it is NaN. You are probably looking for Number.isNaN which checks wether it is not of type number or NaN.
Polyfills:
Global.isNaN = n => +n !== +n;
Number.isNaN = n => typeof n !== "number" || n !== n;
They will behave the same for NaN, numbers, strings and objects, and will behave different for Booleans and strings representing numbers (the global one returns false, the number one true).
Just adding to the correct explanations given about isNan with a solution to your problem:
Instead of using isNan() to identify a number, you could just use typeof which will help you identify the type of the variable:
var b = "44" //this is a string
if ( typeof b === "number" ) {
alert("b is a number"); // does not give me the alert
}
//But if you put an else statement to this
else {
alert("b is NOT a number"); //alerts as b is a number when it's a string
}
The isNaN() function determines whether a value is NaN or not. Note: coercion inside the isNaN function has interesting rules; you may alternatively want to use Number.isNaN(), as defined in ECMAScript 2015.
...
Since the very earliest versions of the isNaN function specification, its behavior for non-numeric arguments has been confusing. When the argument to the isNaN function is not of type Number, the value is first coerced to a Number. The resulting value is then tested to determine whether it is NaN. Thus for non-numbers that when coerced to numeric type result in a valid non-NaN numeric value (notably the empty string and boolean primitives, which when coerced give numeric values zero or one), the "false" returned value may be unexpected; the empty string, for example, is surely "not a number." The confusion stems from the fact that the term, "not a number", has a specific meaning for numbers represented as IEEE-754 floating-point values. The function should be interpreted as answering the question, "is this value, when coerced to a numeric value, an IEEE-754 'Not A Number' value?"
The latest version of ECMAScript (ES2015) contains the Number.isNaN() function. Number.isNaN(x) will be a reliable way to test whether x is NaN or not. Even with Number.isNaN, however, the meaning of NaN remains the precise numeric meaning, and not simply, "not a number". Alternatively, in absense of Number.isNaN, the expression (x != x) is a more reliable way to test whether variable x is NaN or not, as the result is not subject to the false positives that make isNaN unreliable.
Source: isNaN on MDN
From the Specification:
18.2.3 isNaN(number)
The isNaN function is the %isNaN% intrinsic object. When the isNaN function is called with one argument number, the following steps are taken:
Let num be ToNumber(number).
ReturnIfAbrupt(num).
If num is NaN, return true.
Otherwise, return false.
Source: ECMA-262 6th Edition - 18.2.3 isNaN(number)
I always thought that JavaScript's if statements did some kind of casting magic to their arguments, but I'm a little wary of what's actually going on behind the scenes.
I recently found a JavaScript comparison table and noticed that even though -1 == true evaluates to false, if(-1){...} will execute.
So within JavaScripts if statements, what happens to the expression? It seems reasonable to assume that it uses !!{expression} to cast it to an inverse boolean, then invert it again, but if that's the case, how does JS decide whether an object's inverse boolean representation is truthy or not?
JavaScript is wonky.
Yes, -1 == true results in false, but that's not what the if statement is doing. It's checking to see if the statement is 'truthy', or converts to true. In JavaScript, that's the equivalent of !!-1, which does result in true (all numbers other than zero are truthy).
Why?!?
The spec defines the double equals operator to do the following when presented with a number and a boolean:
If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
ToNumber will convert the boolean true into the number 1, so you're comparing:
-1 == 1
which anyone can tell you is clearly false.
On the other hand, an if statement is calling ToBoolean, which considers any non-zero, non-NaN number to be true.
Any JavaScript developer really needs to look at the documentation -- for this case, located here: http://www.ecma-international.org/ecma-262/5.1/#sec-9.2
9.2 ToBoolean
The abstract operation ToBoolean converts its argument to a value of type Boolean according to Table 11:
Argument Type Result
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
(Sorry about the formatting, can't make a table here.)
From JavaScript The Definitive Guide
The following values convert to, and therefore work like, false:
undefined
null
0
-0
NaN
"" // the empty string
All other values, including all objects (and arrays) convert to, and work like, true. false, and the six values that convert to it, are sometimes called falsy values, and all other values are called truthy.
These things by themselves are falsy (or evaluate to false):
undefined
null
0
'' or ""
false
NaN
Everything else i truthy.
Truthy-ness or falsy-ness is used when evaluating a condition where the outcome is expected to be either truthy (true) or falsy (false).
In your example if(-1 == true), you are comparing apples and oranges. The compare is evaluated first (and resulted in false), and the results of that is used in your condition. The concept of truthyness/falsyness isn't applied to the operands the comparison.
When if state using with comparing variable different type js use .toString и .valueOf ( for more information check http://javascript.info/tutorial/object-conversion ) - just keep this in mind - it make so example much more easy to understand
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.
Why does the Javascript function call isNaN(123.) return false? (notice the dot (.) after 123). Is this a universally acceptable number or will it cause errors downstream?
I'm validating whether a value is a valid decimal using isNaN along with split. Are there cross-browser issues with isNaN? Should I use a bespoke implementation?
Thanks.
In JavaScript the grammar of a Numeric Literal is expressed like this:
DecimalIntegerLiteral . DecimalDigitsopt ExponentPartopt
As you can see the DecimalDigits part after the dot is optional (opt suffix).
var n = 123.;
typeof n; // "number"
I wouldn't recommend the isNaN function to detect numbers, since type coercion can make some things look strange:
isNaN(""); // false, a empty string coerces to zero
isNaN("\n\t"); // false, a white-space string coerces to zero
isNaN(true); // false, boolean true coerces to 1
isNaN(false); // false, boolean false coerces to zero
isNaN(new Date); // false, Date objects coerce to its numeric timestamp
// etc...
isNaN should be used only to compare against NaN, since:
NaN == NaN; // false!
IsNaN(NaN); // true
If you want to detect Number objects, Number values or "parseable" numeric strings, give a look to this function I've posted some time ago.
NaN or (not a number) is a particular floating-point value, meaning a value that cannot be represented by computers (using the IEEE 754 floating point standard).
Crucially for you, the isNaN() function makes a best-effort to translate numbers to floating-point, which is why your example returns true. See, for example:
isNaN(100); //Returns false
isNaN("100"); //Returns false
isNaN("ABC"); //Returns true
isNaN("10C"); //Returns true
isNaN(Math.sqrt(-1)); //Returns true
If you want to access a number such as "123." as a float, try using parseFloat():
parseFloat("123."); //Returns 123
Furthermore, 123. is a valid number in javascript, which doesn't require a fractional part after the decimal point. So isNan() is behaving correctly, and should return false in this case.
The function is called "is Not a Number". So, this should return false in case you enter a number and true if it isn't. Even with the dot behind it this number is still valid. 123. just validates as 123 or 123.0.
In JavaScript, why does isNaN(" ") evaluate to false, but isNaN(" x") evaluate to true?
I’m performing numerical operations on a text input field, and I’m checking if the field is null, "", or NaN. When someone types a handful of spaces into the field, my validation fails on all three, and I’m confused as to why it gets past the isNaN check.
JavaScript interprets an empty string as a 0, which then fails the isNAN test. You can use parseInt on the string first which won't convert the empty string to 0. The result should then fail isNAN.
You may find this surprising or maybe not, but here is some test code to show you the wackyness of the JavaScript engine.
document.write(isNaN("")) // false
document.write(isNaN(" ")) // false
document.write(isNaN(0)) // false
document.write(isNaN(null)) // false
document.write(isNaN(false)) // false
document.write("" == false) // true
document.write("" == 0) // true
document.write(" " == 0) // true
document.write(" " == false) // true
document.write(0 == false) // true
document.write(" " == "") // false
so this means that
" " == 0 == false
and
"" == 0 == false
but
"" != " "
Have fun :)
To understand it better, please open Ecma-Script spec pdf on page 43 "ToNumber Applied to the String Type"
if a string has a numerical syntax, which can contain any number of white-space characters, it can be converted to Number type. Empty string evaluates to 0. Also the string 'Infinity' should give
isNaN('Infinity'); // false
Try using:
alert(isNaN(parseInt(" ")));
Or
alert(isNaN(parseFloat(" ")));
From MDN reason for the issue you are facing
When the argument to the isNaN function is not of type Number, the value is first coerced to a Number. The resulting value is then tested to determine whether it is NaN.
You may want to check the following comprehensive answer which covers the NaN comparison for equality as well.
How to test if a JavaScript variable is NaN
I think it's because of Javascript's typing: ' ' is converted to zero, whereas 'x' isn't:
alert(' ' * 1); // 0
alert('x' * 1); // NaN
The Not-Entirely-Correct Answer
Antonio Haley's highly upvoted and accepted answer here makes a wrong assumption that this process goes through JavaScript's parseInt function:
You can use parseInt on the string ... The result should then fail isNAN.
We can easily disprove this statement with the string "123abc":
parseInt("123abc") // 123 (a number...
isNaN("123abc") // true ...which is not a number)
With this, we can see that JavaScript's parseInt function returns "123abc" as the number 123, yet its isNaN function tells us that "123abc" isn't a number.
The Correct Answer
ECMAScript-262 defines how the isNaN check works in section 18.2.3.
18.2.3 isNaN (Number)
The isNaN function is the %isNaN% intrinsic object. When the isNaN function is called with one argument number, the following steps are taken:
Let num be ? ToNumber(number).
If num is NaN, return true.
Otherwise, return false.
The ToNumber function it references is also defined in ECMAScript-262's section 7.1.3. In here, we get told how JavaScript handles Strings which are passed in to this function.
The first example given in the question is a string containing nothing but white space characters. This section states that:
A StringNumericLiteral that is empty or contains only white space is converted to +0.
The " " example string is therefore converted to +0, which is a number.
The same section also states:
If the grammar cannot interpret the String as an expansion of StringNumericLiteral, then the result of ToNumber is NaN.
Without quoting all of the checks contained within that section, the " x" example given in the question falls into the above condition as it cannot be interpreted as a StringNumericLiteral. " x" is therefore converted to NaN.
If you would like to implement an accurate isNumber function, here is one way to do it from Javascript: The Good Parts by Douglas Crockford [page 105]
var isNumber = function isNumber(value) {
return typeof value === 'number' &&
isFinite(value);
}
The function isNaN("") performs a String to Number type coercion
ECMAScript 3-5 defines the following return values for the typeof operator:
undefined
object (null, objects, arrays)
boolean
number
string
function
Better to wrap our test in a function body:
function isNumber (s) {
return typeof s == 'number'? true
: typeof s == 'string'? (s.trim() === ''? false : !isNaN(s))
: (typeof s).match(/object|function/)? false
: !isNaN(s)
}
This function is not intented to test variable type, instead it tests the coerced value. For instance, booleans and strings are coerced to numbers, so perhaps you may want to call this function as isNumberCoerced()
if there's no need to test for types other than string and number, then the following snippet might be used as part of some condition:
if (!isNaN(s) && s.toString().trim()!='') // 's' can be boolean, number or string
alert("s is a number")
NaN !== "not a number"
NaN is a value of Number Type
this is a definition of isNaN() in ECMAScript
1. Let num be ToNumber(number).
2. ReturnIfAbrupt(num).
3. If num is NaN, return true.
4. Otherwise, return false.
Try to convert any value to Number.
Number(" ") // 0
Number("x") // NaN
Number(null) // 0
If you want to determine if the value is NaN, you should try to convert it to a Number value firstly.
I suggest you to use the following function if you really want a proper check if it is an integer:
function isInteger(s)
{
return Math.ceil(s) == Math.floor(s);
}
That isNaN(" ") is false is part of the confusing behavior of the isNaN global function due to its coercion of non-numbers to a numeric type.
From MDN:
Since the very earliest versions of the isNaN function specification, its behavior for non-numeric arguments has been confusing. When the argument to the isNaN function is not of type Number, the value is first coerced to a Number. The resulting value is then tested to determine whether it is NaN. Thus for non-numbers that when coerced to numeric type result in a valid non-NaN numeric value (notably the empty string and boolean primitives, which when coerced give numeric values zero or one), the "false" returned value may be unexpected; the empty string, for example, is surely "not a number."
Note also that with ECMAScript 6, there is also now the Number.isNaN method, which according to MDN:
In comparison to the global isNaN() function, Number.isNaN() doesn't suffer the problem of forcefully converting the parameter to a number. This means it is now safe to pass values that would normally convert to NaN, but aren't actually the same value as NaN. This also means that only values of the type number, that are also NaN, return true.
Unfortunately:
Even the ECMAScript 6 Number.isNaN method has its own issues, as outlined in the blog post - Fixing the ugly JavaScript and ES6 NaN problem.
The isNaN function expects a Number as its argument, so arguments of any other type (in your case a string) will be converted to Number before the actual function logic is performed. (Be aware that NaN is also a value of type Number!)
Btw. this is common for all built-in functions - if they expect an argument of a certain type, the actual argument will be converted using the standard conversion functions. There are standard conversions between all the basic types (bool, string, number, object, date, null, undefined.)
The standard conversion for String to Number can be invoked explicit with Number(). So we can see that:
Number(" ") evaluates to 0
Number(" x") evaluates to NaN
Given this, the result of the isNaN function is completely logical!
The real question is why the standard String-to-Number conversion works like it does. The string-to-number conversion is really intended to convert numeric strings like "123" or "17.5e4" to the equivalent numbers. The conversion first skips initial whitespace (so " 123" is valid) and then tries to parse the rests as a number. If it is not parseable as a number ("x" isn't) then the result is NaN. But there is the explicit special rule that a string which is empty or only whitespace is converted to 0. So this explains the conversion.
Reference: http://www.ecma-international.org/ecma-262/5.1/#sec-9.3.1
I'm not sure why, but to get around the problem you could always trim whitespace before checking. You probably want to do that anyway.
I wrote this quick little function to help solve this problem.
function isNumber(val) {
return (val != undefined && val != null && val.toString().length > 0 && val.toString().match(/[^0-9\.\-]/g) == null);
};
It simply checks for any characters that aren't numeric (0-9), that aren't '-' or '.', and that aren't undefined, null or empty and returns true if there's no matches. :)
As other explained the isNaN function will coerce the empty string into a number before validating it, thus changing an empty string into 0 (which is a valid number).
However, I found that the parseInt function will return NaN when trying to parse an empty string or a string with only spaces. As such the following combination seems to be working well:
if ( isNaN(string) || isNaN(parseInt(string)) ) console.log('Not a number!');
This check will work for positive numbers, negative numbers and numbers with a decimal point, so I believe it covers all common numerical cases.
This function seemed to work in my tests
function isNumber(s) {
if (s === "" || s === null) {
return false;
} else {
var number = parseInt(s);
if (number == 'NaN') {
return false;
} else {
return true;
}
}
}
What about
function isNumberRegex(value) {
var pattern = /^[-+]?\d*\.?\d*$/i;
var match = value.match(pattern);
return value.length > 0 && match != null;
}
The JavaScript built-in isNaN function, is - as should be expected by default - a "Dynamic Type Operator".
Therefore all values which (during the DTC process) may yield a simple true | false such as "", " ", " 000", cannot be NaN.
Meaning that the argument supplied will first undergo a conversion as in:
function isNaNDemo(arg){
var x = new Number(arg).valueOf();
return x != x;
}
Explanation:
In the top line of the function body, we are (first) trying to successfully convert the argument into a number object. And (second), using the dot operator we are - for our own convenience - immediately stripping off, the primitive value of the created object.
In the second line, we are taking the value obtained in the previous step, and the advantage of the fact that NaN is not equal to anything in the universe, not even to itself, e.g.: NaN == NaN >> false to finally compare it (for inequality) with itself.
This way the function return will yield true only when, and only if, the supplied argument-return, is a failed attempt of conversion to a number object, i.e., a not-a-number number; e.g., NaN.
isNaNstatic( )
However, for a Static Type Operator - if needed and when needed - we can write a far simpler function such as:
function isNaNstatic(x){
return x != x;
}
And avoid the DTC altogether so that if the argument is not explicitly a NaN number, it will return false. Wherefore, testing against the following:
isNaNStatic(" x"); // will return false because it's still a string.
However:
isNaNStatic(1/"x"); // will of course return true. as will for instance isNaNStatic(NaN); >> true.
But contrary to isNaN, the isNaNStatic("NaN"); >> false because it (the argument) is an ordinary string.
p.s.:
The static version of isNaN can be very useful in modern coding scenarios. And it may very well be one of the main reasons I took my time for posting this.
Regards.
isNAN(<argument>) is a function to tell whether given argument is illegal number.
isNaN typecasts the arguments into Number type. If you want to check if argument is Numeric or not? Please use $.isNumeric() function in jQuery.
That is, isNaN(foo) is equivalent to isNaN(Number(foo))
It accepts any strings having all numerals as numbers for obvious reasons. For ex.
isNaN(123) //false
isNaN(-1.23) //false
isNaN(5-2) //false
isNaN(0) //false
isNaN('123') //false
isNaN('Hello') //true
isNaN('2005/12/12') //true
isNaN('') //false
isNaN(true) //false
isNaN(undefined) //true
isNaN('NaN') //true
isNaN(NaN) //true
isNaN(0 / 0) //true
I use this
function isNotANumeric(val) {
if(val.trim && val.trim() == "") {
return true;
} else {
return isNaN(parseFloat(val * 1));
}
}
alert(isNotANumeric("100")); // false
alert(isNotANumeric("1a")); // true
alert(isNotANumeric("")); // true
alert(isNotANumeric(" ")); // true
When checking if certain string value with whitespace or " "is isNaN maybe try to perform string validation, example :
// value = "123 "
if (value.match(/\s/) || isNaN(value)) {
// do something
}
I find it convenient to have a method specific to the Number class (since other functions that do conversions like parseInt have different outputs for some of these values) and use prototypal inheritance.
Object.assign(Number.prototype, {
isNumericallyValid(num) {
if (
num === null
|| typeof num === 'boolean'
|| num === ''
|| Number.isNaN(Number(num))
) {
return false;
}
return true;
}
});
I use the following.
x=(isNaN(parseFloat(x)))? 0.00 : parseFloat(x);
let isNotNumber = val => isNaN(val) || (val.trim && val.trim() === '');
console.log(isNotNumber(' '));
console.log(isNotNumber('1'));
console.log(isNotNumber('123x'));
console.log(isNotNumber('x123'));
console.log(isNotNumber('0'));
console.log(isNotNumber(3));
console.log(isNotNumber(' x'));
console.log(isNotNumber('1.23'));
console.log(isNotNumber('1.23.1.3'));
if(!isNotNumber(3)){
console.log('This is a number');
}