为什么加法的隐式强制总是产生一个字符串?

Why does implicit coercion for addition always produce a string?

如果只有第二个操作数是一个字符串,那么输出是一个字符串:

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

如果只有第一个操作数是字符串,那么输出仍然是字符串:

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

我猜会有某种参数优先级。这个数学函数默认为具有混合类型参数的非数字输出是有原因的吗?

当单个运算符是表达式的一部分时,表达式从左到右执行,但在 JavaScript 中,如果与 + 运算符一起使用的任何一个操作数是字符串,另一个将转换为字符串 - 哪个都无关紧要。这是因为 + 操作可能意味着字符串加法(串联)或数学加法。当一个操作数是一个字符串时,JavaScript 运行时正确地假定 + 应该意味着字符串加法,因为该字符串可能包含一个非数字值并且用非数字值进行数学计算是有问题的,也就是说最少。

您需要在连接发生之前对非字符串进行转换。这可以通过多种方式完成:

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

基本运算符优先级为:

  • 括号
  • 指数
  • 乘法
  • 加法
  • 减法

因此,在以下示例中,您可以看到发生的情况:

// 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);

有关运算符及其优先级的完整列表,请参阅 JavaScript Operator Precedence

请参阅 Unary + Operator 了解如何使用它转换为数字。

另请注意,我们在这里不是在谈论 "arguments"(参数是传递给方法或函数的内容)。这些是表达式中的 操作数 operators.

通常情况下,答案是 "because the spec says so"。更具体地说,section 11.6.1 The Addition operator ( + ).

第7步,你可以阅读

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)

换句话说,如果至少一个操作数是字符串,则结果将是两个操作数的字符串表示形式的串联。

在某种程度上存在优先级,因为如果两个操作数都是函数,那么左边的将在右边的之前被评估,但是对于决定 + 操作是否应该 return 字符串或数字。

注意:我参考了 ECMAScript 5 规范,但您可以在较新版本中找到等效内容。