问题
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?
回答1:
As it is often the case, the answer is "because the spec says so". More specifically, section 11.6.1 The Addition operator ( + ).
On step 7, you can read
If Type(lprim) is String or Type(rprim) is String, then
Return the String that is the result of concatenating ToString(lprim) followed by ToString(rprim)
In other words, if at least one of the operands is a string, the result will be the concatenation of the string representation of both operands.
There is precedence in a way, because if both operands were functions the left one would be evaluated before the right one, but it doesn't matter for the algorithm that decides if the +
operation should return a string or a number.
Note: I referred to the ECMAScript 5 spec but you can find something equivalent in the newer versions.
回答2:
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.
来源:https://stackoverflow.com/questions/50867329/why-does-implicit-coercion-for-addition-always-produce-a-string