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

Nir*_*Nir 65 javascript string numbers operators

我不明白为什么JavaScript以这种方式工作.

console.log("1" + 1);
console.log("1" - 1);
Run Code Online (Sandbox Code Playgroud)

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

Ber*_*ann 96

字符串连接完成,+因此Javascript将第一个数字1转换为字符串并连接"1"和"1"使"11".

你不能对字符串执行减法,因此Javascript将第二个"1"转换为数字并从1减去1,结果为零.

  • 只是为了记录,JavaScript中一行开头的一个开括号是一个块,而不是一个对象文字; 所以`[] + {}`和`{} + []`实际上是两个完全不同的陈述 (9认同)
  • @YuryTarabanko好的.连接(所以不添加)*总是*组合2个字符串.所以,如果你尝试做`[] + {}`,你基本上做`[] .toString()+({}).toString()`(因为JavaScript在连接它们之前将所涉及的数组和对象转换为字符串).并且,因为`[].toString ===''和`({}).toString()==='[object Object]'`,你的最终结果为[[] + {} ==='[ object object]'`.这是完全合乎逻辑的. (7认同)
  • @ Joeytje50对.怎么样`{} + []`?:)继续应用相同的逻辑:) (4认同)
  • @ Joeytje50哈哈,那不是真正的*逻辑.如果"对象和数组既不能连接也不能加起来",那么为什么`[] + {}执行连接而`{} + []`不执行连接?另外,你的"对象没有数值"的陈述是假的:`+ {}`返回'NaN`.而'NaN + 0`是'NaN`,而不是'0`.就像@Yury所说的那样,从实际情况或常识的角度讨论JavaScript类型强制是没有意义的. (4认同)
  • @YuryTarabanko因为对象和数组既不能连接也不能相加,所以将这两个按此顺序放在一起会导致数组转换为数字而不是字符串,因为`+`符号位于它前面(就像` + new Date`返回`Date`对象的数值(UNIX时间戳),或`+ true`返回'true`的数值,即'1`).因此,加法变为"{} + 0".因为该对象没有数值,所以它变为"+ 0",JavaScript输出为"0". (3认同)
  • 现在尝试将此逻辑应用于`[] + {}`和`{} + []`:) (2认同)
  • @Izkata完全正确!不要依赖JavaScript的内置类型强制.如果要将两个变量的内容一起添加,请首先确保它们是相同的类型.因为如果你不这样做,JavaScript会. (2认同)
  • @YuryTarabanko:当然,您可以将相同的逻辑应用于“({} + [])”(带括号以消除歧义)。如果你的意思是`{}; +[]`,那么这显然是一个一元加运算符。 (2认同)

Nie*_*sol 33

+很暧昧.它可以表示"连接" "添加".由于一边是一个字符串,它被认为是"连接",因此结果是11(顺便说一下,这是我小时候最喜欢的笑话之一.那和"1 + 1 =窗口",如同视觉上示出:??? ? ?)

-但是只有一个含义:减去.所以它减去了.

这种问题在其他语言中并不存在,例如PHP,其中"连接" .代替+,而不是模棱两可.像MySQL这样的其他语言甚至没有连接运算符,而是使用CONCAT(a,b,c...).

  • 避免此问题的另一个解决方案(以及JavaScript中也出现的许多其他问题)是不允许隐式转换.例如,当你尝试类似上面的东西时,Python会抛出错误,这首先避免了所有这些不直观的问题.动态类型语言中的隐式转换是一个可怕的想法. (7认同)

Yur*_*nko 23

因为规范明确告诉这样做.第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天中这是一个好主意. (3认同)

day*_*oli 8

+既是数字变量的加法运算,也是字符串的连接运算符.

只要在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,其中之前的所有内容都-被视为一个字符串(因为它包含一个字符串".",然后将该术语-视为一个数字.


Sal*_*n A 7

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

"1" +  1  // "11"
 1  + "1" // "11"
 1  +  1  // 2
Run Code Online (Sandbox Code Playgroud)

连接没有反面(我认为),减法运算符-只执行减法而不管操作数的类型如何:

"1" -  1  // 0
 1  - "1" // 0
 1  -  1  // 0
"a" -  1  // NaN
Run Code Online (Sandbox Code Playgroud)

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


Giu*_*Pes 5

根据标准 EcmaScript 262。当涉及字符串时,+and运算符的行为有所不同。-第一个将每个值转换为字符串。第二个将每个值转换为数字。

从标准来看:

如果 Type(lprim) 是 String 或 Type(rprim) 是 String,则返回 ToString(lprim) 和 ToString(rprim) 连接的结果字符串

该规则意味着,如果表达式中存在字符串值,则所有参与运算的值都+将转换为字符串。在 JavaScript 中,当+运算符与字符串一起使用时,它将连接它们。这就是为什么console.log("5"+1)返回“51”的原因。1转换为字符串,然后将“5”+“1”连接在一起。

然而,上述规则并不适用于-运营商。当您使用 a 时,-所有值都会根据标准转换为数字(见下文)。因此,在这种情况下,"5"被转换为5然后1减去。

从标准来看:

5 令 lnum 为 ToNumber(lval)。

6 设 rnum 为 ToNumber(rval)。


标准 EcmaScript 262 中的运算符定义。

运营商+http ://www.ecma-international.org/ecma-262/5.1/#sec-11.6.1 运算符+定义

运营商 -http ://www.ecma-international.org/ecma-262/5.1/#sec-11.6.2 运算符 - 定义