Why does JavaScript handle the plus and minus operators between strings and numbers differently?

27,394

Solution 1

String concatenation is done with + so Javascript will convert the first numeric 1 to a string and concatenate "1" and "1" making "11".

You cannot perform subtraction on strings, so Javascript converts the second "1" to a number and subtracts 1 from 1, resulting in zero.

Solution 2

+ is ambiguous. It can mean "concatenate" or "add". Since one side is a string, it is taken to mean "concatenate", hence the result is 11 (which, by the way, was one of my favourite jokes as a young child. That and "1 + 1 = window", as shown visually: │┼│ ニ ⊞)

- however has only one meaning: subtract. So it subtracts.

This kind of problem is not present in other languages such as PHP, where "concatenate" is . instead of +, making no ambiguity. Still other languages like MySQL don't even have a concatenation operator, instead using CONCAT(a,b,c...).

Solution 3

Because the spec explicitly tells to do so. Page 75. Note the difference between 11.6.1 steps 5-8 and 11.6.2 steps 5-7.

11.6.1 - describes how addition operator works

1-4. ...

5. Let lprim be ToPrimitive(lval).

6. Let rprim be ToPrimitive(rval).

7. If Type(lprim) is String or Type(rprim) is String, then

7a. Return the String that is the result of concatenating ToString(lprim) followed by ToString(rprim)

8. Return the result of applying the addition operation to ToNumber(lprim) and ToNumber(rprim)

11.6.2 - describes how subtraction operator works

1-4. ...

5. Let lnum be ToNumber(lval).

6. Let rnum be ToNumber(rval).

7. Return the result of applying the subtraction operation to lnum and rnum

Summary In case of addition if any of the operands when converted to primitive value without any hints suddenly becomes a string the second one is converted to a string too. In case of subtraction both operands are converted to a number.

Solution 4

There is no dedicated string concatenation operator in JavaScript**. The addition operator + performs either string concatenation or addition, depending on the type of operands:

"1" +  1  // "11"
 1  + "1" // "11"
 1  +  1  // 2

There is no opposite of concatenation (I think) and the subtraction operator - only performs subtraction regardless of the type of operands:

"1" -  1  // 0
 1  - "1" // 0
 1  -  1  // 0
"a" -  1  // NaN

** The . operator in PHP and & operator in VB are dedicated string concatenation operators.

Solution 5

+ is both an addition operator for numeric variables, and a concatenation operator for strings.

Whenever there's a string after a +, Javascript will choose to use the + as a concatenation operator and convert (typed) as many terms as possible around the string so it can concatenate them. That's just the behaviour of Javascript. (If you tried console.log(23 + 2 + "." + 1 + 5 + "02" + 02);, you'll get the result 25.15022. The number 02 was typed into the string 2 before being concatenated.

- can only be a subtraction operator, so when given a string, it will implicitly change the type of the string "1" into a numeric 1; if it didn't do that, there's no way "1" - 1 would make sense. If you tried console.log(23 + 2 + 1 + 5 - "02" + 03); you'll get 32 - the string 02 gets converted into the number 2. The term after the - must be able to be converted into a number; if you tried console.log(23 - 2 - "." - 1 - 5 - 02 - "02"); you'll get NaN returned.

More importantly, if you tried console.log(23 + 2 + "." + 1 + 5 - "02" + 03);, it will output 26.15, where everything before - was treated as a string (because it contains a string ".", and then the term after the - is treated as a number.

Share:
27,394

Related videos on Youtube

Nirgn
Author by

Nirgn

BY DAY: Full Stack Software Engineer @ webintPro BY NIGHT: A Ninja Favorite quote: "We choose to go to the moon. We choose to go to the moon in this decade and do the other things, not because they are easy, but because they are hard, because that goal will serve to organize and measure the best of our energies and skills, because that challenge is one that we are willing to accept, one we are unwilling to postpone, and one which we intend to win, and the others, too." - John F. Kennedy

Updated on October 09, 2020

Comments

  • Nirgn
    Nirgn over 3 years

    I don't understand why JavaScript works this way.

    console.log("1" + 1);
    console.log("1" - 1);
    

    The first line prints 11, and the second prints 0. Why does JavaScript handle the first as a String and the second as a number?

    • Admin
      Admin almost 10 years
      +1 - although the answer why is obvious for anybody accustomed with JS, the reason why the obvious answer is true is still beyond my comprehension - and I suppose I'm not the only one... JS fails POLA in many ways sigh stackoverflow.com/questions/9032856/…
    • DLeh
      DLeh almost 10 years
      I feel like this link should be posted along with any javascript typing weirdness: destroyallsoftware.com/talks/wat
    • gen_Eric
      gen_Eric almost 10 years
      @DLeh: I was just about to post a link to that video :D
    • Simon Forsberg
      Simon Forsberg almost 10 years
      Also related: Your Language Sucks
  • Yury Tarabanko
    Yury Tarabanko almost 10 years
    @Joeytje50 For example, go ahead and try to fantasize why [] + [] === "" :) Is it due to ambiguity about concatenation vs. addition? LOL
  • Yury Tarabanko
    Yury Tarabanko almost 10 years
    Now try to apply this logic to [] + {} and {} + [] :)
  • Joeytje50
    Joeytje50 almost 10 years
    @YuryTarabanko Okay. Concatenation (so not addition) always puts together 2 strings. So, if you try to do [] + {}, you basically do [].toString() + ({}).toString() (because JavaScript converts the involved array and object to a string before concatenating them). And, because [].toString === '' and ({}).toString() === '[object Object]', your final result for [] + {} === '[object Object]'. It's perfectly logical.
  • Yury Tarabanko
    Yury Tarabanko almost 10 years
    @Joeytje50 Right. What about {} + []? :) Go ahead apply the same logic :)
  • Joeytje50
    Joeytje50 almost 10 years
    @YuryTarabanko Because objects and arrays can neither be concatenated nor added up, putting these 2 together in this order causes the array to be converted to a number instead of a string, because the + sign is in front of it (like how +new Date returns the numerical value of the Date object (the UNIX timestamp), or +true returns the numerical value of true, which is 1). Because of that, the addition becomes {} + 0. Because the object doesn't have a numerical value, this becomes +0, which JavaScript outputs as 0.
  • Joeytje50
    Joeytje50 almost 10 years
    @YuryTarabanko either way, it's not important if a certain bit of logic can be applied everywhere, as long as it answers the original question, it is already enough. Nobody will ever use + for adding together objects or arrays, so this is not even a problem in practical situations, whereas adding together / subtracting a string and a number is.
  • Yury Tarabanko
    Yury Tarabanko almost 10 years
    @Joeytje50 OK. No point to continue the conversation when it comes to "practical situations" and common sense :)
  • Voo
    Voo almost 10 years
    Another solution to avoid this problem (and many other problems that also arise in JavaScript) is to not allow implicit conversions. Python for example will just throw an error when you try something like the above which avoids all these unintuitive problems in the first place. Implicit conversions in a dynamically typed language is a horrible idea.
  • Ajedi32
    Ajedi32 almost 10 years
    @Joeytje50 Haha, well that's not really the same logic. If "objects and arrays can neither be concatenated nor added up", then why would [] + {} perform concatenation whereas {} + [] doesn't? Plus, your statement that "object doesn't have a numerical value" is false: +{} returns NaN. And NaN + 0 is NaN, not 0. Like @Yury said though, it's pointless to discuss JavaScript type coercion from the standpoint of practical situations or common sense.
  • James Long
    James Long almost 10 years
    Just for the record, an opening brace at the beginning of a line in JavaScript is a block, not an object literal; so [] + {} and {} + [] are actually two completely different statements
  • Izkata
    Izkata almost 10 years
    @Ajedi32 Force them all to numbers first and you'll get what you expect: +{} + +[] === NaN - confusion typically comes from Javascript's "try this first and if it works, yay! If not, try something else". It just so happens that strings are tried first
  • Ajedi32
    Ajedi32 almost 10 years
    @Izkata Exactly! Don't rely on JavaScript's built-in type coercion. If you want to add the contents of two variables together, first make sure that they're the same type. Because if you don't, JavaScript will.
  • Matteo Italia
    Matteo Italia almost 10 years
    +1 because this is the only authoritative answer. All the rest may be useful mnemonics, but the ultimate answer is "because the spec says so", and it says so because Brendan Eich thought it was a good idea in those infamous 10 days.
  • Bergi
    Bergi almost 10 years
    @YuryTarabanko: Of course you can apply the very same logic to ({} + []) (with parenthesis to remove the ambiguity). If you mean {}; +[], then that's obviously a unary plus operator.
  • Admin
    Admin about 8 years
    Like it when people read and quote specifications and manuals. Thanks.