Why does parseInt fail to test Arrays properly in Javascript? - javascript

Given:
var obj={0:21,1:22}
and
var arr=[21,22]
Why does parseInt(obj) return NaN, but parseInt(arr) returns 21?
I had a function where I was either going to pass an int, a hash type object or a plain array. I was expecting parseInt to return NaN for both object and array, thus simplifying argument checking. What gives?

This is because parseInt tries to coerce the first argument to a string before parsing to an integer. String(obj) returns "[object Object]" and can't be parsed, but String([21,23]) returns "21,23", which parseInt parses until it reaches the unparseable char.
See the parseInt spec:
Let inputString be ? ToString(string).
(Coerce the input to a string).
If S contains a code unit that is not a radix-R digit, let Z be the substring of S consisting of all code units before the first such code unit; otherwise, let Z be S.
(Drop any part of the string starting with non-digit character, so "21,23" -> "21").

Related

How is JavaScript Engine changing the type of Array Object to String

let arr = [1,2,3];
let empArr =[];
for(var i =0; i< arr.length;i++){
console.log('First',typeof empArr);
empArr+=arr[i];
console.log('Second',typeof empArr)
}
The above code gives this output
First object
Second string
First string
Second string
First string
Second string
Could anyone explain how in first iteration type was Array Object then after that it became string.How Javascript Engine works here?
If we run typeof empArr, we will see empArr an object. No matter if we declare it as an array, internally, it is an object. Further, typeof arr[i] shows arr[i] is a number. Therefore, empArr+=arr[i] means we are trying to add an object and a number. Since we are trying to add two different types, it can happen with the help of coercion, implicitly. Coercion means, converting a value of one type to another. JavaScript performs implicit coercion as per the following rules:
operand + operand = result
If at least one operand is an object, it is converted to a primitive
value (string, number or boolean);
After conversion, if at least one operand is string type, the second operand is converted to and the concatenation is executed;
In other case both operands converted to numbers and arithmetic addition is executed.
Note that the primitive value of an array or object is a string.
In our case, empArr is of type object and by rule 1, it is coerced as a string. Now by rule 2, the arr[i] which is a number, is coerced to a string as well and get assigned to empArr.
For more details:
JavaScript addition operator in details
JavaScript type coercion
According to javascript,
typeof [] is "object" ,i.e., every array is actually an object.
if you append anything to a string it will become a string
"1"+1 will equal "11"
It's because of auto type conversion.
The += is a not an array operator, and as the second operand is string - the 1st is converted to string.
Use empArr.push(arr[i])

why parseInt() in javascript converting "1abc" to 1?

I am trying to understand how parseInt() will work in javascript, my scenarios are
var x = parseInt("123");
console.log(x); // outputs 123
var x = parseInt("1abc");
console.log(x); // outputs 1
var x = parseInt("abc");
console.log(x); // outputs NaN
as of my observation parseInt() converts a string to integer(not really an integer of string like "12sv") when the string begins with number.
but in reality it should return NaN.
From: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt
"If the first character cannot be converted to a number, parseInt returns NaN."
From Mozilla's docs: "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."
So it will parse up to the first invalid character, drop the rest of the string, and return the int it managed to parse until then. If there's no valid characters it will return NaN.
parseInt()->it simply parse the provided value to its equivalent radix conversion,if specified without radix it converts to decimal equivalent.
for coercion purpose, we should avoid using parseInt,we can use Number() function instead.

parseInt() parses number literals with exponent incorrectly

I have just observed that the parseInt function doesn't take care about the decimals in case of integers (numbers containing the e character).
Let's take an example: -3.67394039744206e-15
> parseInt(-3.67394039744206e-15)
-3
> -3.67394039744206e-15.toFixed(19)
-3.6739e-15
> -3.67394039744206e-15.toFixed(2)
-0
> Math.round(-3.67394039744206e-15)
0
I expected that the parseInt will also return 0. What's going on at lower level? Why does parseInt return 3 in this case (some snippets from the source code would be appreciated)?
In this example I'm using node v0.12.1, but I expect same to happen in browser and other JavaScript engines.
I think the reason is parseInt converts the passed value to string by calling ToString which will return "-3.67394039744206e-15", then parses it so it will consider -3 and will return it.
The mdn documentation
The parseInt function converts its first argument to a string, parses
it, and returns an integer or NaN
parseInt(-3.67394039744206e-15) === -3
The parseInt function expects a string as the first argument. JavaScript will call toString method behind the scene if the argument is not a string. So the expression is evaluated as follows:
(-3.67394039744206e-15).toString()
// "-3.67394039744206e-15"
parseInt("-3.67394039744206e-15")
// -3
-3.67394039744206e-15.toFixed(19) === -3.6739e-15
This expression is parsed as:
Unary - operator
The number literal 3.67394039744206e-15
.toFixed() -- property accessor, property name and function invocation
The way number literals are parsed is described here. Interestingly, +/- are not part of the number literal. So we have:
// property accessor has higher precedence than unary - operator
3.67394039744206e-15.toFixed(19)
// "0.0000000000000036739"
-"0.0000000000000036739"
// -3.6739e-15
Likewise for -3.67394039744206e-15.toFixed(2):
3.67394039744206e-15.toFixed(2)
// "0.00"
-"0.00"
// -0
If the parsed string (stripped of +/- sign) contains any character that is not a radix digit (10 in your case), then a substring is created containing all the other characters before such character discarding those unrecognized characters.
In the case of -3.67394039744206e-15, the conversion starts and the radix is determined as base 10 -> The conversion happens till it encounters '.' which is not a valid character in base 10 - Thus, effectively, the conversion happens for 3 which gives the value 3 and then the sign is applied, thus -3.
For implementation logic - http://www.ecma-international.org/ecma-262/5.1/#sec-15.1.2.2
More Examples -
alert(parseInt("2711e2", 16));
alert(parseInt("2711e2", 10));
TO note:
The radix starts out at base 10.
If the first character is a '0', it switches to base 8.
If the next character is an 'x', it switches to base 16.
It tries to parse strings to integers. My suspicion is that your floats are first getting casted to strings. Then rather than parsing the whole value then rounding, it uses a character by character parsing function and will stop when it gets to the first decimal point ignoring any decimal places or exponents.
Some examples here http://www.w3schools.com/jsref/jsref_parseint.asp
parseInt has the purpose of parsing a string and not a number:
The parseInt() function parses a string argument and returns an
integer of the specified radix (the base in mathematical numeral
systems).
And parseInt calls the function ToString wherein all the non numerical characters are ignored.
You can use Math.round, which also parses strings, and rounds a number to the nearest integer:
Math.round("12.2e-2") === 0 //true
Math.round("12.2e-2") may round up or down based on the value. Hence may cause issues.
new Number("3.2343e-10").toFixed(0) may solve the issue.
Looks like you try to calculate using parseFloat, this will give you the correct answer.
parseInt as it says, returns an integer, whereas parseFloat returns a floating-point number or exponential number:
parseInt(-3.67394039744206e-15) = -3
parseFloat(-3.67394039744206e-15) = -3.67394039744206e-15
console.log('parseInt(-3.67394039744206e-15) = ' , parseInt(-3.67394039744206e-15));
console.log('parseFloat(-3.67394039744206e-15) = ',parseFloat(-3.67394039744206e-15));

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.

How the string.charAt() works when passing in a string as argument?

According to the MDN JS Doc, the charAt method takes in an integer and returns an the character at the index. And
If the index you supply is out of range, JavaScript returns an empty string.
What I found is that it also takes string as an argument and the return value is intriguing.
The example code: http://jsfiddle.net/yangchenyun/4m3ZW/
var s = 'hey, have fun here.'
>>undefined
s.charAt(2);
>>"y" //works correct
s.charAt('2');
>>"y" //This works too
s.charAt('a');
>>"h" //This is intriguing
Does anyone have a clue how this happens?
The algorithm is described in Section 15.5.4.4 in the specification. There you will see (pos being the parameter passed to charAt):
(...)
3. Let position be ToInteger(pos).
(...)
ToInteger is described in Section 9.4:
Let number be the result of calling ToNumber on the input argument.
If number is NaN, return +0.
(...)
'a' is not a numerical string and hence cannot be converted to a number, so ToNumber will return NaN (see Section 9.3.1) which then results in 0.
On the other side, if you pass a valid numerical string, such as '2', ToNumber will convert it to the corresponding number, 2.
Bottom line:
s.charAt('a') is the same as s.charAt(0), because 'a' cannot be converted to an integer.

Categories