【问题标题】:Why does JavaScript handle the plus and minus operators between strings and numbers differently?为什么 JavaScript 以不同的方式处理字符串和数字之间的加号和减号运算符?
【发布时间】:2014-08-14 13:08:47
【问题描述】:

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

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

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

【问题讨论】:

  • +1 - 虽然 why 的答案对于任何习惯使用 JS 的人来说都是显而易见的,但 为什么显而易见的答案是正确的 的原因仍然超出我的理解- 我想我不是唯一一个...... JS 在很多方面都失败了 POLA sigh stackoverflow.com/questions/9032856/…
  • 我觉得这个链接应该与任何 javascript 打字怪异一起发布:destroyallsoftware.com/talks/wat
  • @DLeh:我正要发布该视频的链接:D
  • 也相关:Your Language Sucks

标签: javascript string numbers operators


【解决方案1】:

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

你不能对字符串进行减法运算,所以 Javascript 将第二个“1”转换为一个数字,并从 1 中减去 1,得到零。

【讨论】:

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

+ 不明确。它可以表示“连接”“添加”。由于一侧是一个字符串,它被认为是“连接”,因此结果是 11(顺便说一句,这是我小时候最喜欢的笑话之一。那和“1 + 1 = 窗口”,如直观显示:│┼│ ニ ⊞)

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

这种问题在PHP等其他语言中不存在,其中“连接”是.而不是+,没有歧义。还有其他语言,如 MySQL,甚至没有连接运算符,而是使用 CONCAT(a,b,c...)

【讨论】:

  • 避免这个问题(以及 JavaScript 中也出现的许多其他问题)的另一个解决方案是不允许隐式转换。例如,当您尝试类似上述的方法时,Python 只会抛出一个错误,这首先避免了所有这些不直观的问题。动态类型语言中的隐式转换是一个可怕的想法。
【解决方案3】:

因为the spec 明确要求这样做。 第 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) 的结果的 String

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

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

1-4。 ...

5。令 lnum 为 ToNumber(lval)。

6。设 rnum 为 ToNumber(rval)。

7。返回对 lnum 和 rnum 进行减法运算的结果

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

【讨论】:

  • @Joeytje50 例如,继续尝试想象为什么[] + [] === "" :) 是由于连接与加法的歧义吗?哈哈
  • +1 因为这是唯一的权威答案。其余的可能都是有用的助记符,但最终的答案是“因为规范是这么说的”,之所以这么说是因为 Brendan Eich 认为在那些臭名昭著的 10 天里这是一个好主意。
【解决方案4】:

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

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

连接没有对立面(我认为),减法运算符- 只执行减法,而与操作数的类型无关:

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

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

【讨论】:

    【解决方案5】:

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

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

    【讨论】:

      【解决方案6】:

      根据标准 EcmaScript 262。+- 运算符在涉及字符串时表现不同。第一个将每个值转换为字符串。第二个将每个值转换为数字。

      来自标准:

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

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

      不过,上述规则不适用于- 运算符。当您使用- 时,所有值都会根据标准转换为数字(见下文)。因此,在这种情况下,"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

      【讨论】:

      • 喜欢人们阅读和引用规范和手册。谢谢。
      【解决方案7】:

      使用加号和字符串"" 基本上会返回一个字符串,因为您正在执行连接:

      typeof ("" + 1 + 0)  // string
      typeof (1 + 0)  // number
      

      当使用 - 时,您可以转换为数字,因为字符串连接是可能的:

      typeof ("" - 1 + 0) // number
      

      【讨论】:

        猜你喜欢
        • 2011-11-02
        • 1970-01-01
        • 2019-03-16
        • 1970-01-01
        • 1970-01-01
        • 2021-12-07
        • 1970-01-01
        • 1970-01-01
        • 2021-05-10
        相关资源
        最近更新 更多