Why do strings sometimes get changed to numbers in javascript? - javascript

I have this code:
function getSessionGUID() {
return (S4()+S4());
}
function S4() {
return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
}
It clearly returns a string, but if you run it a bunch of times, you can notice that it sometimes returns infinity.
for (var i = 0; i < 100000; i++){ if(getSessionGUID() == Infinity) console.log("INFINITY"); }
871 x INFINITY
I then noticed that if you remove the |0, it solves the problem:
function S4() {
return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
}
Results:
for (var i = 0; i < 100000; i++){ if(getSessionGUID() == Infinity) console.log("INFINITY"); }
undefined
Why does this happen? In both cases the value is changed into a string.

You are generating hexidecimal strings.
When you use the == operator, the interpreter tries to coerce the two values to the same data type. When comparing strings to Infinity, that intermediate data type is Number. When those strings contain the letter "e" (a valid hexidecimal digit) and they're coerced to a Number, javascript interprets this as 10^x which ends up as some huge number.
Numbers in javascript are 8 bytes, so anything larger than 1.7976931348623157e308 is considered equal to Infinity.
The easiest way to fix this is to change your == to === so the string doesn't get coerced to a number.
if(getSessionGUID() === Infinity)
http://jsfiddle.net/Uhkxm/

This test reveals the answer:
for (var i = 0; i < 100000; i++){
var x=getSessionGUID();
if(x == Infinity) console.log(x); }
}
It logs values like 61e93284 or 1413e390
These values are valid numbers and they are way too big for the Number type, so they get cast as Infinity when interpreted as a number.
If you replace == with === in the test, no conversion occurs and nothing is logged. The conversion is caused by the == operator.

I think I figured it out. There's actually nothing wrong in all of this, except on my test code.
If you take this string "11e51354", you can get it to assert to true since Javascript checks for all the types that could make it equal to true.
"11e51354" == Infinity # True
The right test would be:
"11e51354" === Infinity # False
It's still a string, but somehow while I was sending it through a GET request, it was being transformed into a number type which gave Infinity.

JavaScript is dynamically typed. There isn't an integer, floating point. String data type. All of that conversions is done internally depending on the context.
The + could be string concatenation or addition depending on context.
Edit: Apologies. Too late. But it was the == performing the conversion to number when comparing against infinity. In some cases, you generated valid numbers.

If you really need a number type, you always could use following.
console.log(Number("1"));

Related

Javascript: Why won't my values equal up? [duplicate]

This question already has answers here:
How to get numeric value from a prompt box? [duplicate]
(6 answers)
Closed 5 years ago.
var check = true;
var number = Math.floor(Math.random() * 20);
while (check === true){
var guess = prompt("I picked a number 0 to 20, try to guess it!");
if (number === guess) {
print("You guessed correctly! Good job!");
check = false;
}
else if (number < guess) {
print("\n\You guessed too high!");
}
else if (number > guess) {
print("\n\You guessed too low!");
}
else {
print("\n\Error. You did not type a valid number");
exit();
}
print("\n\Guess: " + guess + ".");
}
When I try running this program, I get all the way up to the correct answer, but it doesn't work! Even if the randomly generated number is 13, and I guessed 13, it would go through and it would say it is invalid.
Your guess is a string. It is the text entered by the user you need to convert it into a number in order to be able compare it with your guess so replace
var guess = prompt("I picked a number 0 to 20, try to guess it!");
with
var guess = Number(prompt("I picked a number 0 to 20, try to guess it!");
This will turn your guess from your user into a number or a special value NaN if it isn't formatted correctly.
You could also use the == operator which will automatically convert between types. I would recommend against using the operator if you are new to javascript as it can have some confusing and unexpected behaviors.
You are comparing the return value of prompt (a string) with the return value of Math.floor (a number).
Since you are using === and they are different data types, you'll never get a match.
Use == or explicitly cast the number to a string or vice versa.
number === +guess
=== is strictly typed so it will not compare the int to a string.
Convert guess to an integer. You should first validate it though in case the user inputs something other than an int.
var guessInt = +guess; // the plus converts to an integer
if(isNaN(guessInt))
continue;
if (number === guessInt) {
print("You guessed correctly! Good job!");
check = false;
}
You are using the triple = operator which checks for type equalness too. when you compare the prompt value (your guess variable) to your number variable. you are comparing a String and a Number. To make this work you could use
number == guess
or
Number(guess)
You’re using strict equality comparison, which also compares types.
prompt returns string values. Use parseInt to cast to a number.
var guess = prompt("I picked a number 0 to 20, try to guess it!");
guess = parseInt(guess, 10);
The second parameter tells the number base (10 is for decimal, 16 for hexadecimal, etc.). In non strict mode (aka sloppy mode) you may experience accidental conversion to octal (base 8) when parsing strings with a leading zero. Always specify the base to avoid this.
You might want to learn more about JavaScript strict mode.

Why does Number < String returns true in JavaScript?

EDIT: I will rephrase my question, I type Number < String and it returns true, also works when I do typeof(2) < typeof("2").
Number < String => true
typeof(2) < typeof("2") => true
I'm guessing it is the value of ASCII characters of each letter in Number and String but I am not sure if that is the reason this is returning true, and I want to know why does this happens, what processes or how does the interpreter gets to this result?
First answer:
The charCodeAt() method returns the numeric Unicode value of the character at the given index. Read here
Now if you do not specify any index position then character at 0th index is considered. Now, S ASCII value is 83 and N ASCII value is 78. so, you are getting those number. Check here.
And 78 < 83 => true is obvious.
Try "String".charCodeAt(1) and you will get 116 which is ASCII value of t
Second answer based on OP's edited question:
Frankly speaking your comparison Number < String is "technically" incorrect because Less-than Operator < or any similar operator is for expressions, and Number and String are functions and not expressions. However #Pointy explained on how Number < String worked and gave you results.
More insight on comparison operators
Comparison operators like < works on expressions, read here. Typically, you should have a valid expression or resolved value for RHS and LHS.
Now this is the definition of expression, read more here - "An expression is any valid unit of code that resolves to a value. Conceptually, there are two types of expressions: those that assign a value to a variable and those that simply have a value."
So, (x = 7) < (x = 2) or new Number() < new String() is a "technically" valid/good comparison, even this Object.toString < Number.toString() but really not Object < Function.
Below are rules/features for comparisons, read more here
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 distinct objects are never equal for either strict or abstract comparisons.
An expression comparing Objects is only true if the operands reference the same Object.
Null and Undefined Types are strictly equal to themselves and abstractly equal to each other.
The result of
Number < String
is not the result of comparing the strings "Number" and "String", or not exactly that. It's the result of comparing the strings returned from Number.toString() and String.toString(). Those strings will (in all the runtimes I know of) have more stuff in them than just the strings "Number" and "String", but those two substrings will be the first place that they're different.
You can see what those actual strings are by typing
Number.toString()
in your browser console.
JavaScript does the following thing:
"String".charCodeAt(); => 83
"S".charCodeAt(); => 83
"String".charCodeAt(0); => 83
The method charCodeAt(a) gets the char code from position a. The default value is 0
If you compare N > S you will get 78 > 83 => true
For the complete String Javascript calculates the sum of all ASCII char codes.
So I can answer your question with yes.

What does the "Number" function do in JavaScript?

var num = Number(prompt("Pick a number", "0"));
if (num < 10)
alert("Small");
else if (num < 100)
alert("Medium");
else
alert("Large");
I'm just confused about what the Number is doing in this code.
What will happen if I make it like this:
var num = prompt("Pick a number", "0");
Number converts the passed value to a number value. Examples:
> Number(10)
10
> Number("10")
10
> Number(true)
1
> Number("0x11")
17
> Number("foo")
NaN
It performs explicit type conversion to a number.
There is also String and Boolean which do basically the same, but convert to a string and boolean instead.
What will happen if I make it like this ...
prompt will always return a string value. However, in your specific example, it wouldn't actually make a difference because the relational comparison operator (<) will perform the same type conversion implicitly. I.e.
a < 10
// is the same as
Number(a) < 10
Still, I'd say it's good practice to perform explicit type conversion, since it makes it clearer in the rest of the code what type you expect.
Note: It is also possible to call Number with new, i.e. new Number(...), however, that will return a number object instead of primitive number value. This is rarely used.

Which is the safest way to discriminate 0 from empty string in JavaScript?

From user input, I receive a string which must contain numbers. 0 and empty string must be treated differently.
I've made this brief case study
0 == "" // true
parseInt(0) == "" // true
parseInt("") // NaN
parseInt("") == "NaN" // false
parseInt("") == NaN // false
typeof parseInt("") // "number"
With a bit of extra research I've made up this solution (considering uInput the user input)
function userInput(uInput){
var n = parseInt(uInput);
if (isNan(n))
// empty string
else
// 0 or number
}
It looks like it is able to distinguish 0 from empty string correctly in Google Chrome.
What I'd like to know is:
Is this the best/most efficient solution?
Is this solution compatible in any browser?
Is this even a solution at all? Is there any way n can become
something other than a number (considering uInput could be any kind of string)?
I wouldn't be asking this, but since empty string and 0 are treated the same (?!) I don't know to which other holes is my code potentialy exposed.
I'd do something like this:
var nmbr = parseInt(uInput, 10);
if (!isNaN(nmbr)) {
// Yay, valid input!
} else {
// Ups, weird input...
}
This seems the simplest and most correct answer, because parseInt only returns an integer or NaN.
I would go with the ===, try it like: 0 === "" // false
The difference about them and about type conversions read:
Q: Does it matter which equals operator (== vs ===) I use in JavaScript comparisons?
Is this even a solution at all? Is there any way n can become something other than a number?
Yes. parseInt only does consider the first, integer part of the string when parsing it. It ignores the rest, so "12.34 oops" will still validate as 12.
I receive a string which must contain numbers
You can use a simple regex to test that:
/^\d+$/.test(uInput)
It will yield true for strings that consists of only (and at least one) digits, and false for anything else (non-numeric and empty strings).
Create your own test, you do like a million try for each and retrieve the time it takes.
For browser compatibility, I guess simple operation should be alike.
Try this:
function validate(uInput){
var regEx = /^[1-9]{1}[\d]*$/;
if (regEx.test(uInput))
alert(uInput + " is a valid number.");
else
alert(uInput + " is not valid number.");
var validNumber = parseInt(uInput);
}
0 == "" // true
because of == which does a type coercion first:
0 == false, "" == false so false == false.
you should be using ===, where
0 === "" // false
without type coercion.

Javascript Checking for NaN - Results not as expected

I have an application that reads in a number via ajax, the number is hexadecimal and I parse it and convert to decimal.
The numbers come in through a wireless serial link and are not 100% reliable so I need to check them before I start processing the data. The numbers take the form ****025781610403e5**** for example. The **** is just a way of checking the start and end of the number that I have used in the past with non web based projects and could be changed.
Anyway to my question at last: As part of error checking I thought I would check for NaN as I do get NaN errors when I have been testing but while *1234 gives a positive NaN 12**34 does not, why is that? and what else can I do to test?
Here is some of the code I have used, please note I am fairly new to javascript.
function readSliceConvert()
{
functionReadForm()
testVal = hexString.slice(4,18);
document.getElementById("battDb4").innerHTML=testVal;
testNum1 = h2d(testVal)
document.getElementById("battDb5").innerHTML=testNum1.toString();
testNum2 = parseInt(testVal);
document.getElementById("battDb6").innerHTML=testNum2.toString();
if (isNaN(testNum2))
{
errorCount++;
document.getElementById("battDb3").innerHTML=errorCount.toString();
document.getElementById("battDb4").innerHTML=testVal;
return;
}
}
That's because you are using parseInt, it will silently ignore characters at the end of the string when there are some digit in the beginning of the string that it can parse.
I don't know what your h2d function is doing, but it seems that you are converting the hexadecimal string to a number, then to a string in decimal form, then back to a number. I don't see any reason why the output of parsing the hexadecimal string couldn't be a number.
For example like this, returning null if the parsing fails:
function h2i(str) {
var num = 0;
var digits = "0123456789abcdef";
str = str.toLowerCase();
for (var i = 0; i < str.length; i++) {
var n = digits.indexOf(str.substr(i, 1));
if (n == -1) return null;
num = num * 16 + n;
}
return num;
}
Demo: http://jsfiddle.net/Guffa/6yAaP/
Usage:
testVal = hexString.slice(4,18);
document.getElementById("battDb4").innerHTML = testVal;
testNum = h2i(testVal)
document.getElementById("battDb5").innerHTML = testNum.toString();
if (testNum == null)
{
errorCount++;
document.getElementById("battDb3").innerHTML = errorCount.toString();
document.getElementById("battDb4").innerHTML = testVal;
return;
}
Do you know what parseInt() does?
From MDN
parseInt is a top-level function and is not associated with any
object.
The parseInt function converts its first argument to a string, parses
it, and returns an integer or NaN. If not NaN, the returned value will
be the decimal integer representation of the first argument taken as a
number in the specified radix (base). For example, a radix of 10
indicates to convert from a decimal number, 8 octal, 16 hexadecimal,
and so on. For radices above 10, the letters of the alphabet indicate
numerals greater than 9. For example, for hexadecimal numbers (base
16), A through F are used.
If parseInt encounters a character that is not a numeral in the
specified radix, it ignores it and all succeeding characters and
returns the integer value parsed up to that point. parseInt truncates
numbers to integer values. Leading and trailing spaces are allowed.
Run the code in the console
console.log( parseInt("12**34",10) );
So you are running isNaN against a number since parseInt returns 12.
When you have the * as the first character, there are no leading numbers to return.
console.log( parseInt("*1234",10) );
You're seeing weird behaviour because isNan is broken (see the mozilla docs for details).
A better way to test your data is correctly formatted would be a quick regular expression, like serial.test(/^\d+$/), which will succeed if the entire serial is entirely numeric, or serial.test(/^\*{4}\d+\*{4}$/) which will succeed if the serial is four asterisks, followed by one or more number, followed by another four asterisks.
Update: #Guffa's answer is correct, and should be accepted, but I'll leave this here as I think there's a valid argument in the bigger picture that you could better accomplish what you're trying to do with a regular expression.
Running test on the string executes the supplied regular expression, and returns true if it matches the string.
Regular expressions are just patterns describing text, which can be incredibly complex or as simple as the example I've given (\d+ means match a number (\d) one or more times (+), with anchors for the beginning (^) and end ($) of the string to indicate that we want to match the whole string, not just part of it. They're ridiculously useful, so it's almost certainly worth taking the time to learn the basics of how they work, and expand you knowledge over time. There's a great tutorial on regular-expressions.info that'll get you started in no time.

Categories