为什么 JavaScript 以不同的方式处理字符串和数字之间的加减运算符?

IT技术 javascript string numbers operators
2021-01-21 11:22:19

我不明白为什么 JavaScript 是这样工作的。

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

第一行打印 11,第二行打印 0。为什么 JavaScript 将第一行作为字符串处理,第二行作为数字处理?

6个回答

字符串连接是用+Javascript完成的,因此 Javascript 会将第一个数字 1 转换为字符串,并将“1”和“1”连接起来形成“11”。

您不能对字符串执行减法,因此 Javascript 将第二个“1”转换为数字并从 1 中减去 1,结果为零。

@YuryTarabanko 好的。连接(所以不是加法)总是将 2 个字符串放在一起。因此,如果您尝试这样做[] + {},您基本上会这样做[].toString() + ({}).toString()(因为 JavaScript 在连接它们之前将所涉及的数组和对象转换为字符串)。并且,因为[].toString === ''({}).toString() === '[object Object]',你的最终结果[] + {} === '[object Object]'这是完全合乎逻辑的。
2021-03-14 11:22:19
@Joeytje50 哈哈,这不是完全相同的逻辑。如果“对象和数组既不能连接也不能相加”,那么为什么要[] + {}执行连接而{} + []不能呢?另外,您关于“对象没有数值”的说法是错误的:+{}返回NaN而且NaN + 0NaN,不0就像@Yury 所说的那样,从实际情况或常识的角度讨论 JavaScript 类型强制是没有意义的。
2021-03-28 11:22:19
只是为了记录,JavaScript 中一行开头的大括号是一个块,而不是一个对象字面量;所以[] + {}{} + []实际上是两个完全不同的陈述
2021-03-28 11:22:19
@Joeytje50 对。怎么样{} + []:) 继续应用相同的逻辑:)
2021-04-04 11:22:19
@YuryTarabanko 因为对象和数组既不能连接也不能相加,将这两个按这个顺序放在一起会导致数组转换为数字而不是字符串,因为+符号在它前面(比如如何+new Date返回数值的Date对象(UNIX 时间戳),或+true返回 的数值true,即1)。因此,加法变为{} + 0因为对象没有数值,所以它变成了+0,JavaScript 输出为0
2021-04-09 11:22:19

+是模棱两可的。它可以表示“连接”“添加”。由于一侧是一个字符串,所以它表示“连接”,因此结果是 11(顺便说一下,这是我小时候最喜欢的笑话之一。那个和“1 + 1 = 窗口”,如视觉上示出:│┼│ ニ ⊞

-然而只有一个意思:减法。所以它减去。

此类问题在其他语言中不存在,例如 PHP,其中“连接”.代替了+,因此不会产生歧义。还有其他语言(如 MySQL)甚至没有连接运算符,而是使用CONCAT(a,b,c...).

避免此问题(以及 JavaScript 中也出现的许多其他问题)的另一个解决方案是不允许隐式转换。例如,当您尝试像上面这样的操作时,Python 只会抛出一个错误,这首先避免了所有这些不直观的问题。动态类型语言中的隐式转换是一个可怕的想法。
2021-03-20 11:22:19

因为规范明确要求这样做。第 75 页。注意 11.6.1 步骤 5-8 和 11.6.2 步骤 5-7 之间的区别。

11.6.1 - 描述加法运算符的工作原理

1-4. ...

5. 令 lprim 为 ToPrimitive(lval)。

6. 令 rprim 为 ToPrimitive(rval)。

7. 如果 Type(lprim) 是 String 或者 Type(rprim) 是 String,那么

7a. 返回作为连接 ToString(lprim) 后跟 ToString(rprim) 的结果的字符串

8. 返回对 ToNumber(lprim) 和 ToNumber(rprim) 应用加法运算的结果

11.6.2 - 描述减法运算符的工作原理

1-4. ...

5. 令 lnum 为 ToNumber(lval)。

6. 令 rnum 为 ToNumber(rval)。

7. 返回对 lnum 和 rnum 应用减法运算的结果

总结 在加法的情况下,如果任何操作数在没有任何提示的情况下转换为原始值时突然变成字符串,第二个操作数也会转换为字符串。在减法的情况下,两个操作数都转换为数字。

+1 因为这是唯一的权威答案。其余的可能都是有用的助记符,但最终的答案是“因为规范是这样说的”,而且是因为 Brendan Eich 认为在那些臭名昭著的 10 天里这是个好主意。
2021-03-26 11:22:19
@Joeytje50 例如,继续并尝试幻想为什么[] + [] === "":) 是由于连接与加法的含糊不清吗?哈哈
2021-03-30 11:22:19

JavaScript** 中没有专门的字符串连接运算符。加法运算符+执行字符串连接或加法,具体取决于操作数的类型:

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

连接没有对立面(我认为)并且减法运算符-只执行减法而不管操作数的类型:

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

** .PHP 中的&运算符和 VB 中的运算符是专用的字符串连接运算符。

+既是数值变量加法运算符,又是字符串串联运算符

每当 a 后面有一个字符串时+,Javascript 将选择将+用作连接运算符并在字符串周围转换(键入)尽可能多的术语,以便将它们连接起来。这只是 Javascript 的行为。(如果你尝试过console.log(23 + 2 + "." + 1 + 5 + "02" + 02);,你会得到结果25.15022。数字在连接之前被02输入到字符串2中。

-只能是减法运算符,所以当给定一个字符串时,它会隐式地将字符串的类型"1"改为数字1如果它不这样做,就没有任何"1" - 1意义。如果你尝试过,console.log(23 + 2 + 1 + 5 - "02" + 03);你会得到 32 - 字符串02被转换成数字2后面的项-必须能够转换成数字;如果你尝试过,console.log(23 - 2 - "." - 1 - 5 - 02 - "02");你会得到NaN回报。

更重要的是,如果您尝试console.log(23 + 2 + "." + 1 + 5 - "02" + 03);,它将输出26.15,其中之前的所有内容都-被视为字符串(因为它包含一个字符串".",然后将 之后的术语-视为数字。