Search code examples
javascriptoperator-precedencecoercion

Why does implicit coercion for addition always produce a string?


If only the second operand in addition is a string then the output is a string:

let a = 1 + '2';
console.log(typeof a);  // string

And if, instead, only the first operand is a string, then the output is still a string:

let b = '1' + 2;
console.log(typeof b);  // string

I was guessing that there would be some kind of argument precedence. Is there a reason why this mathematical function defaults to a non-numerical output with mixed-type arguments?


Solution

  • When a single operator is part of an expression, the expression is performed left to right, but in JavaScript, if any one of the operands used with the + operator is a string, the other one will be converted to a string - it doesn't matter which one. This is because the + operation can mean string addition (concatenation) or mathematical addition. When one operand is a string, the JavaScript runtime correctly assumes that the + should mean string addition because the string could contain a non-numeric value and doing math with non-numeric values is problematic, to say the least.

    You would need to do a conversion on the non-string before the concatenation occurs. This can be done in a number of ways:

    console.log(1 + +"2");              // prepending a + to a string attempts to convert to a number
    
    // Note that with all of the following there is a nested function call being performed
    // and these functions take an argument, which requires () for the argument to be passed.
    // Because of the nested (), that function call is performed first and the result of the 
    // function call is returned to the expression.
    
    console.log(1 + parseInt("2.4"));   // parse the integer portion of the string into a number
    console.log(1 + parseFloat("2.4")); // parse the floating point number in the string into a number
    console.log(1 + Number("2"));       // convert the string into a number

    The basic operator precedence is:

    • Parenthesis
    • Exponents
    • Multiplication
    • Division
    • Addition
    • Subtraction

    So, in the following examples, you can see that happening:

    // Here, the order of operations will be:
    
      // Parenthesis:    (2/2) === 1
      // Multiplication: 10 * 1 === 10
      // Addition:       1 + 10 === 11
      // Subtraction:    11 - 3 === 8
    console.log(1 + 10 * (2 / 2) - 3);
    
    // But here, because of the string, the order of operations will be:
    
      // Parenthesis:    (2/2) === 1
      // Multiplication: 10 * 1 === 10
      // Addition:       "1" + 10 === "110" (one operand is a string, so the other converts to a string)
      // Subtraction:    "110" - 3 === 107  (the string "110" will be implicitly converted to a number
      //                                     becuase the - sign  only has one meaning in a mathmatical 
      //                                     expression)
    console.log("1" + 10 * (2 / 2) - 3);

    See JavaScript Operator Precedence for a full list of operators and their precedence.

    See Unary + Operator for how it is used to convert to a number.

    Also note that we're not talking about "arguments" here (an argument is what is passed to a method or function). These are operands in an expression with operators.