18
Global.alert("base: " + base + ", upfront: " + upfront + ", both: " + (base + upfront));

The code above outputs something like:

base: 15000, upfront: 36, both: 1500036

Why is it joining the two numbers instead of adding them up?

I eventually want to set the value of another field to this amount using this:

mainPanel.feesPanel.initialLoanAmount.setValue(Ext.util.Format.number((base + upfront), '$0,000.00'));

And when I try that, it turns the number into the millions instead of 15,036.00. Why?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Scott
  • 2,143
  • 2
  • 19
  • 25

6 Answers6

30

Simple example:

 1 +1 == 2
"1"+1 == "11"
"1"*1 + 1 == 2

Ways to turn a string into a number:

  • parseInt(str)
  • parseInt(str,10)
  • parseFloat(str)
  • +str
  • str*1
  • str-0
  • str<<0
  • Number(str)

And here are some of the consequences: Results of converting various strings using the above techniques
(source: phrogz.net)

Number(str) has the same behavior as str*1, but requires a function call.

I personally use *1 as it is short to type, but still stands out (unlike the unary +), and either gives me what the user typed or fails completely. I only use parseInt() when I know that there will be non-numeric content at the end to ignore, or when I need to parse a non-base-10 string.

You can test the performance of these in your browser at my example page.

Community
  • 1
  • 1
Phrogz
  • 296,393
  • 112
  • 651
  • 745
  • 2
    +1, `+s` and `s*1` are not only shorthands, but more correct. – David Tang Jan 05 '11 at 04:19
  • 1
    +1. I will add that `Number()` can also give you strange results. For instance, `+" "` and `+""` will result in `0` where `parseInt(" ", 10)` will return `NaN`. `Number()` trims white space before conversion and an empty string after trimming will always result in `0`. Like the ups and downs with other methods, whether this behaviour is desired or not can vary by usage. More often than not, I use `+` (it stands out enough for me) but it's definitely worth making sure that you won't get caught out by what might seem like ghosts in the machine. – Andy E Sep 15 '11 at 16:54
  • thanks @Phrogz for the *1 hint. Im writing a js calculator that uses parsefloat() and works fine with desktop browsers but rounds decimals in mobile browsers (3.14*2 = 6 !!!!). Im going to try this and see if it will make any difference. – AleX_ Apr 04 '16 at 14:51
  • Hi @Phrogz, I tried your "1*" suggestion for parsing floats. It works fine on desktop browsers but not on the mobile browsers that I tried. However, (1.0)* works fine even on mobile FireFox and Chrome. I suggest you include this in your post. Thanks – AleX_ Apr 06 '16 at 16:42
  • @fetah I find that claim improbable, and would need to see a simple example proof before including such information. – Phrogz Apr 06 '16 at 16:43
  • Please see this question: http://stackoverflow.com/questions/36438586/parsefloat-does-not-work-on-mobile-devices/36438785 – AleX_ Apr 06 '16 at 16:57
19

This might happen because they are strings. Try parsing them:

Global.alert(
    "base: " + base + ", upfront: " + upfront + ", both: " + 
    (parseInt(base) + parseInt(upfront))
);

If those numbers are decimal you will need the parseFloat method instead.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
6

Try

Global.alert(
    "base: " + base + ", upfront: " + upfront + ", both: " + 
    (parseInt(base,10) + parseInt(upfront,10))
);

The 10 specifies base 10, otherwise the chance of the value being parsed as octal exists.

davidj
  • 254
  • 2
  • 9
  • Just a minor nit - while you are right about always specifying the base being a good idea, the default base is indeed 10 and not octal. It assumes octal for strings that start from zero (such as `"0120"`). – Chetan S Sep 03 '10 at 17:49
  • So changing from "otherwise it is octal" to "otherwise the chance of the value being parsed as octal exists" would be a good edit? It's all about best practices, right? – davidj Sep 03 '10 at 17:52
1

It's handling it as a string. You need to do your math before the string. Example:

base + upfront + ' string' 

would return "15036 string".

string + base + upfront

would return string 1500036 as you are seeing now.

Or use parseInt().

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mark
  • 5,680
  • 2
  • 25
  • 26
  • He's using parenthesis, so the addition will execute before trying to merge with the other string (i.e. you don't have to do your math "before" the string if you use parenthesis). But, parseInt would work - the **+** operator is treating at least one of his operands as strings. – palswim Sep 03 '10 at 19:15
1

http://jsperf.com/number-vs-parseint-vs-plus/3

That might also be of interest to you. It is just a performance comparison of the methods already mentioned here.

tau
  • 6,499
  • 10
  • 37
  • 60
1

I don't know why the brackets aren't helping you out.
If I try

var base = 500;
var upfront = 100;
alert("base: " + base + ", upfront: " + upfront + ", both: " + (base + upfront))

I do get 600 as the answer, so it could be there is something going on in the Global.alert function?

One of the mistakes of the language design is that + is both an addition operator and a concatenation operator. Coupled with the fact that it is loosely typed and will cast implicitly means that it can give you some nasty surprises unless you take steps to ensure that you really are adding numbers and not concatenating strings. In this case, it is treating your base + upfront as strings and therefore concatenating.

Anyway, the way around it could be to have (base - upfront*-1) instead.

Phrogz
  • 296,393
  • 112
  • 651
  • 745
Dawn
  • 941
  • 6
  • 11