Why is an Array with one Number a Number in Javascript? - javascript

I've found that an empty array or an arwith exactly one Number is a Number.
This topic is not really an explanation for this special case I think: Why does isNaN(" ") equal false
document.write( isNaN([1,2,3]) ); // true
document.write( isNaN([1,2,'abc']) ); // true
document.write( isNaN(['abc']) ); // true
// maybe explained through the above link
document.write( isNaN([]) ); // false
// but...
document.write( isNaN([1]) ); // false
document.write( isNaN([-3]) ); // false
document.write( isNaN([1234567]) ); // false
document.write( isNaN([-1.234]) ); // false
document.write( isNaN([[123]]) ); // false
document.write( isNaN(['1']) ); // false
Who can tell me why it makes sense?

isNaN coerces its value to a number. (See MDN)
Because the string representation of an array is all of its items concatenated with a comma. And the numerical representation of that is NaN because of the comma.
But if there's only one item, hence no comma, it's able to be converted to a number.

You're using the isNaN global function which has some confusing behavior due to its coercion of non-numbers to a numeric type which can then result in the NaN value. This is what is happening in your case as the string representation of an array containing a single number element will successfully parse to the number value of the single number element.
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.

Related

Comparison String to String

I got these 2 examples below -
console.log("a" > "3") // outputs true
console.log("hello" > "3") // outputs true
According to MDN, If both values are strings, they are compared as strings, based on the values of the Unicode code points they contain.
But then they also wrote the following in the next paragraph, Strings are converted based on the values they contain, and are converted as NaN if they do not contain numeric values.
Following this logic, shouldn't both statements be false since no matter what the operator it is, "a" and "hello" are words in strings and they don't have a numerical value, therefore, it should return NaN, and NaN is false; hence, as soon as one of the operands is false, it outputs false?
If I need to adhere to the former statement above, could you please walk me through this logic?
Thanks.
The key phrase from the MDN article is
If both values are strings, […].
Otherwise JavaScript attempts to convert non-numeric types to numeric values
So no, "a", "3" and "hello" are all strings, and when comparing them, they get compared as strings. No conversion to anything occurs.
You are comparing two strings (in quotation marks), not a string to a number. This should answer your question:
"a" > "3" //true
"a" > 3 //false
As you've written,
If both values are strings, they are compared as strings, based on the
values of the Unicode code points they contain
So, on both examples, both values are strings. If you change "3" to 3, the result is:
console.log("a" > 3)
// expected output: false
console.log("hello" > 3)
// expected output: false
That's because, first it's converted as NaN, and then:
If either value is NaN, the operator returns false.
The docs:
If both values are strings, they are compared as strings, based on the values of the Unicode code points they contain.
Otherwise JavaScript attempts to convert non-numeric types to numeric values: ....
Reading the docs, I understand that, if BOTH strings have numerical values (both not NaN), then both are treated as Unicode code points. Otherwise, if BOTH have numerical values, then they're converted.
But anyways, my sugestion for a js beginer: do not get too attached to how the language works for now, and even tho it can compare strings with "greater" and "less than", I dont think there would (or should) be a real life scenario where you would need it.
Also, just for fun, check this pen I made when I first started with js (I was also very confused about comparison and typing xD):
"" == null // this one is fun
Later, after learning more about the language, you'll get why somethings work like they do in js, I also recomending understanding the history of js and the web, it explains a lot of the weird behaviours of the language.

[]+(-~{}-~{}-~{}-~{})+(-~{}-~{}) [duplicate]

This question already has answers here:
Why does ++[[]][+[]]+[+[]] return the string "10"?
(10 answers)
(![]+[])[+[]]... Explain why this works
(1 answer)
Closed 9 years ago.
While reading this article posted on dzone I found a snippet of JavaScript originally posted on Twitter by Marcus Lagergren.
The following code apparently prints the string "fail"
(![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]];
This involves implicit type casting and I'm trying to understand how exactly this line is interpreted.
I've isolated each character
(![]+[])[+[]] prints "f"
(![]+[])[+!+[]] prints "a"
([![]]+[][[]])[+!+[]+[+[]]] prints "i"
(![]+[])[!+[]+!+[]] prints "l"
I've also managed to break down the expressions returning each letter apart from "i"
letter "f"
![] an empty array is an Object, which according to ECMAScript documentation, point 9.2 evaluates to true when converted to a boolean so this is false
false+[] as per Point 11.6.1 both arguments of the binary + operator get converted to String, therefore we get "false"+"", which evaluates "false"
+[] a unary plus operator causes a ToNumber conversion followed by a ToPrimitive conversion if the argument is an Object. The result of such conversion is determined by calling the [[DefaultValue]] internal method of the object. In case of an empty array, it defaults to 0.
(ECMAScript Documentation, sections: 11.4.6, 9.3, 9.1 )
"false"[0] we're accessing the character at index 0, hence the "f"
letter "a"
Same story, the only difference here are additional conversions in the part in square brackets (which evaluates to a number to point at another character in the string "false"), triggered by the use of unary + and ! operators.
+[] evaluates to 0, as explained above.
!0 evaluates to true as defined in Section 9.2 and Section 11.4.9. First, 0 is converted to a boolean false and then the operator inverts the value.
+true again, the unary plus triggers a ToNumber conversion, which returns a 1 for binary true
(Section 11.4.6 and 9.3)
"false"[1] returns the second character in the string, which is "a"
letter "l"
!+[] evaluates to true as explained above
true+true using the binary + on primitives triggers a ToNumber conversion. In case of true, its result is 1 and 1+1 equals 2
"false"[2] - self explanatory
letter "i"
What leaves me stumped is the letter "i". I can see that the second part (in square brackets) evaluates to the string "10" and that the first part (in parentheses) returns "falseundefined" but I can't make heads or tails of how this is happening. Could someone explain it step by step? Especially the magic that happens with square brackets? (arrays and array access)
If possible, I'd like each step to contain a link to the underlying ECMAScript rules.
What I find the most cryptic is this part: [][[]]
Your cryptic part isn't all that cryptic if you rewrite it a little:
[]['']
[] will be coerced into a string because it isn't an integer, so you're looking for a property of [] with the name '' (an empty string). You'll just get undefined, as there is no property with that name.
As for the actual letter, break the expression up into the two main components:
The string ([![]]+[][[]]):
[![]] is [false].
[][[]] is undefined.
Add them together and you get "falseundefined".
And the index: [+!+[]+[+[]]]. Some whitespace and parentheses will make the operations much clearer: [+(!(+[])) + [+[]]]:
[+[]] is [0].
+[] coerces [] to an integer, so you get 0.
!+[] coerces 0 to a boolean and negates it, so you get true.
+!+[] coerces true to an integer, so you get 1.
Add them together, and you get ["10"].
When using a string to access the properties of the array and the string happens to be an element of the array, the string is coerced into an integer and you get back the actual element of the array:
> [1, 2, 3]["0"]
1
> [1, 2, 3]["1"]
2
So your final result is:
> "falseundefined"["10"]
"i"
Read this answer for an explanation of the [false] + undefined part.
([![]]+[][[]])[+!+[]+[+[]]] has two parts :
([![]]+[][[]]) and the other which you found yourself.
![] returns false. Then we use [...] to get the .toString() behavior of +.
([]+[] is the same as [].toString()+[].toString())
the [][[]] is undefined because we're trying to access the index [] (or [].toString(), which is '') of [] which is undefined.
Sorry for the previous answered, I misread your comment totally.

Why does angular.isNumber(NaN) return true? [duplicate]

This question already has answers here:
Why does typeof NaN return 'number'?
(21 answers)
Closed 7 years ago.
NaN represents Not-A-Number.
It appears that angular.isNumber thinks it is a number. (angularjs 1.4.2)
Why does angular.isNumber return true for NaN input?
thanks
Quoting IgorMinar, Angular Developer in this exact question:
$ node
> typeof NaN
'number'
It kind of makes sense if you squint with both eyes and plug your
ears.
If you deliberately use NaN in your app, you should use isNaN instead
of angular.isNumber.
I'm inclined to say that the current behavior, even though a bit
surprising, is consistent with how NaN is being treated in javascript.
If you have some good arguments for changing the behavior please share
them with us.
So the question really goes for the javascript standard itself not for Angular
And to answer this question we must go to ECMAScript 5 specification of number type, of course it says:
4.3.20 Number type
set of all possible Number values including the special “Not-a-Number”
(NaN) values, positive infinity, and negative infinity
4.3.23 NaN
number value that is a IEEE 754 “Not-a-Number” value
So yes, according to the latest ECMAScript Specification i'm a number
Here's the best way that I can think of to explain this.
Although the value of NaN represents something that is not a number, the value NaN itself is still a number type (in the type system sense).
It's also a defined value for a floating point number in IEEE 754, which is what JavaScript uses for numbers. It is sensible that values infinity and NaN would be number types.
The ECMA spec defines NaN as a IEEE 754 Not-a-Number number value. One reason for the NaN global being a number are comparison purposes. It is also needed to represent undefined numerical results, like the value of Math.sqrt(-1). So it’s not particularly AngularJS specific. Consider the following:
typeof NaN === "number" // true
typeof NaN === typeof NaN // true
typeof NaN === typeof 123 // true
NaN === NaN // false
isNaN(NaN) // true
isNaN(123) // false
isNaN('123') // false
isNaN('|23') // true
So isNumber returns true for NaN because it is a Number. To check for numerics, use isNaN().
Most likely angular just uses the type of what you pass in. if the type is number then it returns true.
If you want to know if something is a number (excluding NaN) you can do the following.
function isNumber(val){
return angular.isNumber(val) && (val == val);
}
This works by first determing if val is a number. If it is check to see if it's NaN.
NaN is not equal to itself (or any other number for that matter).
it's not related to angular, it's JavaScript
try this
typeof NaN
it will return number
There are really two meanings of "number" here:
the abbreviation "NaN" means that there is no meaningful answer to a particular mathematical operation; you could say "no such number"
however, every value in a language like JS has a type, and the type of data which goes into and out of mathematical operations is known in JS as "number"; thus when JS wants a special value to say that a mathematical operation has no answer, that special value is a special number
Note that this apparent contradiction is less obvious in other languages, because JS is unusual in having only one numeric type, rather than (at least) integer and real/float types. Having NaN as a floating point value is standard across pretty much all modern languages, but because of the word "number", it perhaps seems more surprising in JS.
The Angular function is one of a set of utilities for testing the type of a value. The documentation for it mentions that it returns true for infinities and NaN, and points to the standard isFinite function for when that's not desirable.

How to inconsistency between parseFloat("") and isNaN("")

I need to check if value isNaN("") === true but it returns false but parseFloat("") returns NaN.
Why I need this is because I am doing hash check with JSON.stringify() and knockout observable instead of numeric value returns a string numeric value.
E.g. Instead of 1.23 it returns "1.23".
Question: How to parse string numeric values without getting NaN as result?
How to parse string numeric values without getting NaN as result?
Well...you can't, if the values can't be parsed as numeric values. But "1.23" can be parsed as a numeric value:
var num = parseFloat("1.23");
console.log(num); // 1.23
If you need to check if the result will be NaN, check the result:
isNaN(parseFloat(yourInput)) === true
...except there is exactly zero point in the === true part of that, so:
isNaN(parseFloat(yourInput))
parseFloat and the default coercion to number used if you pass a string into isNaN follow different rules. In particular, parseFloat will stop parsing as of the first non-numeric, but isNaN [in effect] uses the Number function, which will fail if there are non-numeric characters. So if you need to rely on getting a result from parseFloat that is not NaN, you have to call parseFloat and pass its result into isNaN.
Here's an example: "1.23aaa" Let's see what we see there:
console.log(parseFloat("1.23aaa")); // 1.23
console.log(isNaN("1.23aaa")); // true!!
console.log(isNaN(parseFloat("1.23aaa"))); // false
parseFloat stops trying as of the first a, but the default coercion from string to number you're invoking by passing a string into isNaN doesn't.

isNaN isn't working properly

This is the attribute I put on a text box to restrict input to numbers.
onKeyPress="if(isNaN(String.fromCharCode(event.keyCode))) event.preventDefault();"
Working perfect with google chrome. isNaN function return true for non-numeric keyPress and return false for every numeric keyPress. But in firefox isNaN function return true for both numeric and non-numeric key press's.
I read isNaN function cross-browser supported but it isn't works fine in firefox. What am I doing wrong here?
Confusing special-case behavior with isNaN()
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-794 floating-point values. The function should be interpreted as answering the question, "is this value, when coerced to a numeric value, an IEEE-794 'Not A Number' value?"
The next version of ECMAScript (ES6) contains the function 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.
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
Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN
If your intention is to check that input is a number, a better way to test is to look at the actual value of the input:
onblur="if (/\D/.test(this.value)) alert('there\'s a non-digit in the value');"
The above is "better" as values can be entered without pressing any keys, thereby not causing a keypress event, also the keyCode may resolve to an unexpected value. All you really care about is the value of the control, not how it got there.
Also, please don't restrict what the user can type into the control, just test the value at the time you want to use it (e.g. on form submission or when the control loses focus). Often users will strike an incorrect key and happily fix the error themselves. Throwing up an error or deleting the character automatically before the user has a chance to do it themselve makes the control harder to use, not easier.
Your code
onKeyPress="if(isNaN(String.fromCharCode(event.keyCode))) event.preventDefault();"
will not work on any version of Mozilla browsers, because moz doesn't expose events. No matter how counterintuitive, moz browsers will require a function with a declared argument name, say function(e){...; at which they arbitrary assign the event object on functions triggered by events.
Since you are accessing the event object globally, and it's not there[!], - this declaration
String.fromCharCode(event.keyCode)
will either trigger an error; or Firefox made compromise that when a property of undefined 'event' keyword has been called, to return undefined value which the test
isNaN(undefined);
always evaluate as true.
And that's why you are getting true for all kinds of characters being typed there - be it a letter, or a numeral - regardless.

Categories