What is the difference between Number(...) and parseFloat(...) - javascript

What is the difference between parseInt(string) and Number(string) in JavaScript has been asked previously.
But the answers basically focused on the radix and the ability of parseInt to take a string like "123htg" and turn it into 123.
What I am asking here is if there is any big difference between the returns of Number(...) and parseFloat(...) when you pass it an actual number string with no radix at all.

The internal workings are not that different, as #James Allardic already answered. There is a difference though. Using parseFloat, a (trimmed) string starting with one or more numeric characters followed by alphanumeric characters can convert to a Number, with Number that will not succeed. As in:
parseFloat('3.23abc'); //=> 3.23
Number('3.23abc'); //=> NaN
In both conversions, the input string is trimmed, by the way:
parseFloat(' 3.23abc '); //=> 3.23
Number(' 3.23 '); //=> 3.23

No. Both will result in the internal ToNumber(string) function being called.
From ES5 section 15.7.1 (The Number Constructor Called as a Function):
When Number is called as a function rather than as a constructor, it performs a type conversion...
Returns a Number value (not a Number object) computed by ToNumber(value) if value was supplied, else returns +0.
From ES5 section 15.1.2.3 (parseFloat (string)):
...
If neither trimmedString nor any prefix of trimmedString satisfies the syntax of a StrDecimalLiteral (see 9.3.1)
...
And 9.3.1 is the section titled "ToNumber Applied to the String Type", which is what the first quote is referring to when it says ToNumber(value).
Update (see comments)
By calling the Number constructor with the new operator, you will get an instance of the Number object, rather than a numeric literal. For example:
typeof new Number(10); //object
typeof Number(10); //number
This is defined in section 15.7.2 (The Number Constructor):
When Number is called as part of a new expression it is a constructor: it initialises the newly created object.

Not a whole lot of difference, as long as you're sure there's nothing but digits in your string. If there are, Number will return NaN. Another problem that you might get using the Number constructor is that co-workers might think you forgot the new keyword, and add it later on, causing strict comparisons to fail new Number(123) === 123 --> false whereas Number(123) === 123 --> true.
In general, I prefer to leave the Number constructor for what it is, and just use the shortest syntax there is to cast to an int/float: +numString, or use parse*.

When not using new to create a wrapper object for a numerical value, Number is relegated to simply doing type conversion from string to number.
'parseFloat' on the other hand, as you mentioned, can parse a floating point number from any string that starts with a digit, a decimal, or +/-
So, if you're only working with strings that contain only numerical values, Number(x) and parseFloat(x) will result in the same values

Please excuse me posting yet another answer, but I just got here via a Google search and did not find all of the details that I wanted. Running the following code in Node.js:
var vals = ["1", "1.1", "0", "1.1abc", "", " ", null];
for(var i = 0; i < vals.length; i++){
var ifTest = false;
if(vals[i])
{
ifTest = true;
}
console.log("val=" + vals[i] + ", Number()=" + Number(vals[i])+ ", parseFloat()=" + parseFloat(vals[i]) + ", if()=" + ifTest);
}
gives the following output:
val=1, Number()=1, parseFloat()=1, if()=true
val=1.1, Number()=1.1, parseFloat()=1.1, if()=true
val=0, Number()=0, parseFloat()=0, if()=true
val=1.1abc, Number()=NaN, parseFloat()=1.1, if()=true
val=, Number()=0, parseFloat()=NaN, if()=false
val= , Number()=0, parseFloat()=NaN, if()=true
val=null, Number()=0, parseFloat()=NaN, if()=false
Some noteworthy takeaways:
If protecting with an if(val) before trying to convert to number, then parseFloat() will return a number except in the whitespace case.
Number returns a number in all cases except for non-numeric characters aside from white-space.
Please feel free to add any test cases that I may be missing.

Related

Does JavaScript support automatic type conversion?

There are a few expressions that are commonly seen in JavaScript, but which some programming purists will tell you are never a good idea. What these expressions share is their reliance on automatic type conversion — a core feature of JavaScript which is both a strength and a weakness, depending on the circumstances and your point of view.
Type coercion and type conversion are similar except type coercion is when JavaScript automatically converts a value from one type to another (such as strings to numbers). It's also different in that it will decide how to coerce with its own set or rules. I found this example useful because it shows some interesting output behavior illustrating this coercive behavior:
const value1 = '5';
const value2 = 9;
let sum = value1 + value2;
console.log(sum);
In the above example, JavaScript has coerced the 9 from a number into a string and then concatenated the two values together, resulting in a string of 59. JavaScript had a choice between a string or a number and decided to use a string.
The compiler could have coerced the 5 into a number and returned a sum of 14, but it did not. To return this result, you'd have to explicitly convert the 5 to a number using the Number() method:
sum = Number(value1) + value2;
From an MDN glossary entry I wrote here: https://developer.mozilla.org/en-US/docs/Glossary/Type_coercion edited by chrisdavidmills
Does JavaScript support automatic type conversion?
Yes. It's usually called type coercion, but conversion is perfectly accurate.
For instance:
console.log("Example " + 42);
"automatically" converts 42 (a number) to string. I put "automatically" in quotes because it's done by the + operator, in a clearly-defined way.
Another example is that various operations expecting numbers will convert from string (or even from object). For instance:
const obj = {
valueOf() {
return 2;
}
};
const str = "10";
console.log(Math.max(obj, str)); // 10
console.log(Math.min(obj, str)); // 2
The rules JavaScript uses are clearly and completely defined in the specification. That doesn't prevent people from frequently being surprised by some of them, such as that +"" is 0.

javascript, parseInt behavior when passing in a float number

I have the following two parseInt() and I am not quite sure why they gave me different results:
alert(parseInt(0.00001)) shows 0;
alert(parseInt(0.00000001)) shows 1
My guess is that since parseInt needs string parameter, it treats 0.00001 as ""+0.00001 which is "0.00001", therefore, the first alert will show 0 after parseInt. For the second statement, ""+0.00000001 will be "1e-8", whose parseInt will be 1. Am I correct?
Thanks
I believe you are correct.
parseInt(0.00001) == parseInt(String(0.00001)) == parseInt('0.00001') ==> 0
parseInt(0.00000001) == parseInt(String(0.00000001)) == parseInt('1e-8') ==> 1
You are correct.
parseInt is intended to get a number from a string. So, if you pass it a number, it first converts it into a string, and then back into a number. After string conversion, parseInt starts at the first number in the string and gives up at the first non-number related character. So "1.e-8" becomes "1"
If you know you are starting with a string, and are just trying to get an Integer value, you can do something like.
Math.round(Number('0.00000001')); // 0
If you know you have a floating point number and not a string...
Math.round(0.00000001); // 0
You can also truncate, ceil(), or floor the number
parseInt takes each character in the first argument (converted to a string) that it recognizes as a number, and as soon as it finds a non-numeric value it ignores that value and the rest of the string. (see MDN second paragraph under "Description")
Therefore it's likely that parseInt(0.00000001) === parseInt(String(0.00000001)) === parseInt("1e-8"), which would only extract the 1 from the string yielding parseInt("1") === 1
However, there's another possibility:
From Mozilla developer network:
parseInt(string, radix);
for the string argument (emphasis added): "The value to parse. If string is not a string, then it is converted to one. Leading whitespace in the string is ignored."
I think this possibility is less likely, since String(0.00000001) does not yield NAN.

Why is the number converted to a string (basic Javascript function)

I have this function (going trough the Eloquent Javascript Tutorial chapter 3):
function absolute(number) {
if (number < 0)
return -number;
else
return number;
}
show(absolute(prompt("Pick a number", "")));
If I run it and enter -3 the output will be 3 as expectet but if I enter just 3 the output will be "3" (with double quotes). I can get around by changing
return number;
to
return Number(number);
but why is that necessary? What am I missing?
prompt() always returns a string, but when you enter a negative number, it is handed to the -number call and implicitly converted to a Number. That doesn't happen if you pass it a positive, and the value received by prompt() is returned directly.
You can, as you discovered, cast it with Number(), or you can use parseInt(number, 10), or you could do -(-number) to flip it negative, then positive again, or more obviously as pointed out in comments, +number. (Don't do --number, which will cast it to a Number then decrement it)
Javascript is not strongly typed.
number comes from the prompt() function, which returns a string.
Since you aren't doing anything to change its type, it remains a string.
-number implicitly converts and returns an actual number.
If you have a string that needs to be converted to a number, please do the following:
var numString = '3';
var num = parseInt(numString);
console.log(num); // 3
JavaScript performs automatic conversion between types. Your incoming "number" is most likely string (you can verify by showing result of typeof(number)).
- does not take "string" as argument, so it will be converted to number first and than negated. You can get the same behavior using unary +: typeof(+ "3") is number when typeof("3") is string.
Same happens for binary - - will convert operands to number. + is more fun as it work with both strings "1"+"2" is "12", but 1+2 is 3.

What is the explanation for these bizarre JavaScript behaviours mentioned in the 'Wat' talk for CodeMash 2012?

The 'Wat' talk for CodeMash 2012 basically points out a few bizarre quirks with Ruby and JavaScript.
I have made a JSFiddle of the results at http://jsfiddle.net/fe479/9/.
The behaviours specific to JavaScript (as I don't know Ruby) are listed below.
I found in the JSFiddle that some of my results didn't correspond with those in the video, and I am not sure why. I am, however, curious to know how JavaScript is handling working behind the scenes in each case.
Empty Array + Empty Array
[] + []
result:
<Empty String>
I am quite curious about the + operator when used with arrays in JavaScript.
This matches the video's result.
Empty Array + Object
[] + {}
result:
[Object]
This matches the video's result. What's going on here? Why is this an object. What does the + operator do?
Object + Empty Array
{} + []
result:
[Object]
This doesn't match the video. The video suggests that the result is 0, whereas I get [Object].
Object + Object
{} + {}
result:
[Object][Object]
This doesn't match the video either, and how does outputting a variable result in two objects? Maybe my JSFiddle is wrong.
Array(16).join("wat" - 1)
result:
NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
Doing wat + 1 results in wat1wat1wat1wat1...
I suspect this is just straightforward behaviour that trying to subtract a number from a string results in NaN.
Here's a list of explanations for the results you're seeing (and supposed to be seeing). The references I'm using are from the ECMA-262 standard.
[] + []
When using the addition operator, both the left and right operands are converted to primitives first (§11.6.1). As per §9.1, converting an object (in this case an array) to a primitive returns its default value, which for objects with a valid toString() method is the result of calling object.toString() (§8.12.8). For arrays this is the same as calling array.join() (§15.4.4.2). Joining an empty array results in an empty string, so step #7 of the addition operator returns the concatenation of two empty strings, which is the empty string.
[] + {}
Similar to [] + [], both operands are converted to primitives first. For "Object objects" (§15.2), this is again the result of calling object.toString(), which for non-null, non-undefined objects is "[object Object]" (§15.2.4.2).
{} + []
The {} here is not parsed as an object, but instead as an empty block (§12.1, at least as long as you're not forcing that statement to be an expression, but more about that later). The return value of empty blocks is empty, so the result of that statement is the same as +[]. The unary + operator (§11.4.6) returns ToNumber(ToPrimitive(operand)). As we already know, ToPrimitive([]) is the empty string, and according to §9.3.1, ToNumber("") is 0.
{} + {}
Similar to the previous case, the first {} is parsed as a block with empty return value. Again, +{} is the same as ToNumber(ToPrimitive({})), and ToPrimitive({}) is "[object Object]" (see [] + {}). So to get the result of +{}, we have to apply ToNumber on the string "[object Object]". When following the steps from §9.3.1, we get NaN as a result:
If the grammar cannot interpret the String as an expansion of StringNumericLiteral, then the result of ToNumber is NaN.
Array(16).join("wat" - 1)
As per §15.4.1.1 and §15.4.2.2, Array(16) creates a new array with length 16. To get the value of the argument to join, §11.6.2 steps #5 and #6 show that we have to convert both operands to a number using ToNumber. ToNumber(1) is simply 1 (§9.3), whereas ToNumber("wat") again is NaN as per §9.3.1. Following step 7 of §11.6.2, §11.6.3 dictates that
If either operand is NaN, the result is NaN.
So the argument to Array(16).join is NaN. Following §15.4.4.5 (Array.prototype.join), we have to call ToString on the argument, which is "NaN" (§9.8.1):
If m is NaN, return the String "NaN".
Following step 10 of §15.4.4.5, we get 15 repetitions of the concatenation of "NaN" and the empty string, which equals the result you're seeing.
When using "wat" + 1 instead of "wat" - 1 as argument, the addition operator converts 1 to a string instead of converting "wat" to a number, so it effectively calls Array(16).join("wat1").
As to why you're seeing different results for the {} + [] case: When using it as a function argument, you're forcing the statement to be an ExpressionStatement, which makes it impossible to parse {} as empty block, so it's instead parsed as an empty object literal.
This is more of a comment than an answer, but for some reason I can't comment on your question. I wanted to correct your JSFiddle code. However, I posted this on Hacker News and someone suggested that I repost it here.
The problem in the JSFiddle code is that ({}) (opening braces inside of parentheses) is not the same as {} (opening braces as the start of a line of code). So when you type out({} + []) you are forcing the {} to be something which it is not when you type {} + []. This is part of the overall 'wat'-ness of Javascript.
The basic idea was simple JavaScript wanted to allow both of these forms:
if (u)
v;
if (x) {
y;
z;
}
To do so, two interpretations were made of the opening brace: 1. it is not required and 2. it can appear anywhere.
This was a wrong move. Real code doesn't have an opening brace appearing in the middle of nowhere, and real code also tends to be more fragile when it uses the first form rather than the second. (About once every other month at my last job, I'd get called to a coworker's desk when their modifications to my code weren't working, and the problem was that they'd added a line to the "if" without adding curly braces. I eventually just adopted the habit that the curly braces are always required, even when you're only writing one line.)
Fortunately in many cases eval() will replicate the full wat-ness of JavaScript. The JSFiddle code should read:
function out(code) {
function format(x) {
return typeof x === "string" ?
JSON.stringify(x) : x;
}
document.writeln('>>> ' + code);
document.writeln(format(eval(code)));
}
document.writeln("<pre>");
out('[] + []');
out('[] + {}');
out('{} + []');
out('{} + {}');
out('Array(16).join("wat" + 1)');
out('Array(16).join("wat - 1")');
out('Array(16).join("wat" - 1) + " Batman!"');
document.writeln("</pre>");
[Also that is the first time I have written document.writeln in many many many years, and I feel a little dirty writing anything involving both document.writeln() and eval().]
I second #Ventero’s solution. If you want to, you can go into more detail as to how + converts its operands.
First step (§9.1): convert both operands to primitives (primitive values are undefined, null, booleans, numbers, strings; all other values are objects, including arrays and functions). If an operand is already primitive, you are done. If not, it is an object obj and the following steps are performed:
Call obj.valueOf(). If it returns a primitive, you are done. Direct instances of Object and arrays return themselves, so you are not done yet.
Call obj.toString(). If it returns a primitive, you are done. {} and [] both return a string, so you are done.
Otherwise, throw a TypeError.
For dates, step 1 and 2 are swapped. You can observe the conversion behavior as follows:
var obj = {
valueOf: function () {
console.log("valueOf");
return {}; // not a primitive
},
toString: function () {
console.log("toString");
return {}; // not a primitive
}
}
Interaction (Number() first converts to primitive then to number):
> Number(obj)
valueOf
toString
TypeError: Cannot convert object to primitive value
Second step (§11.6.1): If one of the operands is a string, the other operand is also converted to string and the result is produced by concatenating two strings. Otherwise, both operands are converted to numbers and the result is produced by adding them.
More detailed explanation of the conversion process: “What is {} + {} in JavaScript?”
We may refer to the specification and that's great and most accurate, but most of the cases can also be explained in a more comprehensible way with the following statements:
+ and - operators work only with primitive values. More specifically +(addition) works with either strings or numbers, and +(unary) and -(subtraction and unary) works only with numbers.
All native functions or operators that expect primitive value as argument, will first convert that argument to desired primitive type. It is done with valueOf or toString, which are available on any object. That's the reason why such functions or operators don't throw errors when invoked on objects.
So we may say that:
[] + [] is same as String([]) + String([]) which is same as '' + ''. I mentioned above that +(addition) is also valid for numbers, but there is no valid number representation of an array in JavaScript, so addition of strings is used instead.
[] + {} is same as String([]) + String({}) which is same as '' + '[object Object]'
{} + []. This one deserves more explanation (see Ventero answer). In that case, curly braces are treated not as an object but as an empty block, so it turns out to be same as +[]. Unary + works only with numbers, so the implementation tries to get a number out of []. First it tries valueOf which in the case of arrays returns the same object, so then it tries the last resort: conversion of a toString result to a number. We may write it as +Number(String([])) which is same as +Number('') which is same as +0.
Array(16).join("wat" - 1) subtraction - works only with numbers, so it's the same as: Array(16).join(Number("wat") - 1), as "wat" can't be converted to a valid number. We receive NaN, and any arithmetic operation on NaN results with NaN, so we have: Array(16).join(NaN).
To buttress what has been shared earlier.
The underlying cause of this behaviour is partly due to the weakly-typed nature of JavaScript. For example, the expression 1 + “2” is ambiguous since there are two possible interpretations based on the operand types (int, string) and (int int):
User intends to concatenate two strings, result: “12”
User intends to add two numbers, result: 3
Thus with varying input types,the output possibilities increase.
The addition algorithm
Coerce operands to primitive values
The JavaScript primitives are string, number, null, undefined and boolean (Symbol is coming soon in ES6). Any other value is an object (e.g. arrays, functions and objects). The coercion process for converting objects into primitive values is described thus:
If a primitive value is returned when object.valueOf() is invoked, then return this value, otherwise continue
If a primitive value is returned when object.toString() is invoked, then return this value, otherwise continue
Throw a TypeError
Note: For date values, the order is to invoke toString before valueOf.
If any operand value is a string, then do a string concatenation
Otherwise, convert both operands to their numeric value and then add these values
Knowing the various coercion values of types in JavaScript does help to make the confusing outputs clearer. See the coercion table below
+-----------------+-------------------+---------------+
| Primitive Value | String value | Numeric value |
+-----------------+-------------------+---------------+
| null | “null” | 0 |
| undefined | “undefined” | NaN |
| true | “true” | 1 |
| false | “false” | 0 |
| 123 | “123” | 123 |
| [] | “” | 0 |
| {} | “[object Object]” | NaN |
+-----------------+-------------------+---------------+
It is also good to know that JavaScript's + operator is left-associative as this determines what the output will be cases involving more than one + operation.
Leveraging the
Thus 1 + "2" will give "12" because any addition involving a string will always default to string concatenation.
You can read more examples in this blog post (disclaimer I wrote it).

Why is the result of my calculation undefined?

when I run the javascript code below, I get the variable original as ending as
"1059823647undefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefined0"
why is this happening and how can i fix it?
original="012345678901234567890";
document.write("<textarea>");
document.write(original);
document.write("</textarea>"+"<br>");
/* scramble */
var scramble='1059823647';
scramble=scramble.split('');
var scrambled=new Array();
original=original.split('');
for(i=0;i<original.length;i++){
if(Math.round(Math.round(Math.floor(i/10)*10)+10)>=original.length){
scrambled[i]=original[i];
}else{
scrambled[i]=original[Math.round(Math.round(Math.floor(i/10)*10)+scramble[i%10])];
}
}
original='';
for(i=0;i<scrambled.length;i++){
original+=scrambled[i];
}
document.write("<textarea>");
document.write(original);
document.write("</textarea>"+"<br>");
undefined is being printed because your equation:
Math.round(Math.round(Math.floor(i/10)*10)+scramble[i%10])
is returning a number outside of the range of your array "original"
eg when i = 10, your equation returns 101.
I'm not entirely sure but i think what you mean to do is this:
(Math.floor(i/10)*10) + Number(scramble[i%10])
You're working with strings. But treating them like numbers. JavaScript will convert a string representation of a number to an actual number, but only when it needs to... And the + operator doesn't require such a conversion, as it acts as the concatenation operator for strings.
Therefore, this expression:
Math.round(Math.floor(i/10)*10)+scramble[i%10]
...is converting the first operand into a string and appending an element from the scramble array. You don't notice this for the first ten iterations, since when i<10 the first expression evaluates to 0... But after that, you're suddenly prefixing each scramble element with "10", and trying to access original indexes >= 100... of which there are none defined.
Solution:
Convert your strings to numbers before using them.
Math.round(Math.floor(i/10)*10)+ Number(scramble[i%10])

Categories

Resources