如果在JavaScript中遇到加法(+)运算符,后缀增量如何工作?

时间:2016-01-06 12:25:27

标签: javascript

首先,我知道后面谈到的表达式有side-effects,不应该在生产环境中使用。我只想通过它们了解JavaScript。所有这些都在Chrome下进行了测试。

var a = 42;
var b = "42";
a + ++b; // result is 85 

以下是我对a + ++b

的理解

根据Operator precedencePrefix Increment (++)(优先级15)的优先级高于Addition(+)(优先级13)。可以将++b解析为var ToNumber(GetValue(expr))43,请参阅12.5.7 Prefix Increment Operator。然后,a + 43的结果可能是85

然而,

var a = 42;
var b = "42";
a++ + b; // "4242"

为什么a++ + b的结果是"4242"

我尝试理解结果"4242",似乎a++首先返回42,然后42 + '42'42'42' 1}} var ToString()首先,请参阅12.7.3 The Addition operator ( + )。那么结果可能是"4242"

但它似乎违反了规则:Postfix increment(优先级16)高于Addition(优先级13)???

var a = 42;
var b = "42";
a +++b; // "4242" 

如何解析a +++b;

8 个答案:

答案 0 :(得分:24)

哈哈,狡猾的人!

修复后增量返回相同的值,然后递增变量。 这是我所知道的每种语言的默认行为。

所以,当你这样做时(警告:这不是一个有效的表达,它只是为了表明这个想法):

42++ + "42"

真正发生的是:

  1. ++运算符
  2. 返回第42个
  3. 然后42增加到43
  4. 然后将42(表达式的结果值)强制转换为字符串
  5. 然后将两个操作数连接起来
  6. 编辑#1:

    如果你这样做:

    var a = 42;
    var b = "42";
    a + b++; // result is 84
    

    测试它!

    编辑#2:

    因此,我们总结您的问题与运算符优先级无关(:

答案 1 :(得分:7)

javascript中的post和pre增量与其他语言有所不同。也就是说,这些运算符可以与操作数中的单个空格分开。例如:

var a = 42;
++ a;

注意++和a之间的空格,这也适用于a ++
所以当javascript开始解析语句时,它需要操作数或运算符并将其存储在其堆栈中并找到任何使用它的机会。我希望你知道语言如何解析语句,从左到右或从右到左。 Javascript从左到右解析。
所以,当你写a +++b时,它开始从左边解析,

  

找到一个:推入堆栈;堆栈:[a]
    找到+:堆叠中的push +;堆栈:[a,+]
    找到+:pop +和一个来自堆栈并应用操作数并推送     堆栈上的结果(现在堆栈只有内存,而不是++,因为     后增量);堆栈[a]
    找到+:推进堆栈;堆栈:[a,+]
    找到b:pop +和a from stack,应用操作数并将结果推送到堆栈;堆栈:[b]

不再有操作数或运算符,因此它给出的结果为a+b,并且由于a上的后增量而在其后面增加a, 如果你想在添加之前增加b,你可以试试这个:

a + ++b

这将从++分离+,现在javascript知道应用增量的位置。

答案 2 :(得分:7)

当然,增量/减量运算符 - 一元运算符 - 优先于+(加法/连接)二进制运算符,但我认为这里的问题是强制。让我解释一下:

  

为什么++ + b的结果是4242?

a是数字42,b是字符串'42')

这是因为当您将increment运算符应用于具有数字值('42')的字符串时,结果将被强制转换为数字(42)。

所以现在我们留下了一个表达式number + string(42 + '42'):在这种情况下,+运算符将连接(将数字42强制转换为字符串'42'并产生字符串'4242')。

另一方面:在第一个示例中a + ++ba是数字42而b是字符串'42') - b将被强制转换为数字在增加之后,我们使用number + number(42 + 43) - 因此+运算符将执行addition而不是连接(42 + 43 = 85)

关于下一个问题:

  

a +++ b如何;被解析?

由于将变量和增量操作符与空格分开是合法的,因此解析器将查看a +++b并首先查看a++

此外,由于+运算符在其两个操作数之间不需要空格,因此解析器将使用a++运算符正确分隔操作数b+ 。因此a +++b;将被解析为a++ + b

答案 3 :(得分:5)

@zangw没有什么比++有更高的优先级而不是+。 ++ b是一个预增量运算符,+是一个算术。++ b意味着首先改变一个操作数的值,然后使用它与++相矛盾。 ++总是带有一个操作数,+来自两个操作数,后者是一个操作。希望你明白了吗?

答案 4 :(得分:3)

好问题,请查看ecma standard 12.7.3.1(步骤11)

11. If Type(lprim) is String or Type(rprim) is String, then
   a. Let lstr be ToString(lprim).
   b. ReturnIfAbrupt(lstr).
   c. Let rstr be ToString(rprim).
   d. ReturnIfAbrupt(rstr).
   e. Return the String that is the result of concatenating lstr and rstr

如果运算符之一为string,则两者都转换为字符串,然后执行连接。

答案 5 :(得分:3)

这实际上与运算符优先级无关;它与lexing / parsing有关,它甚至在应用运算符优先级之类的概念之前很久就会发生。 像许多其他语言一样,JavaScript的词法分析器是"贪婪",这意味着可以选择" +"和" ++"将永远选择更长的符号。

答案 6 :(得分:2)

不错的问题,但这里是答案:)。

Bar::firstOrCreate()

答案 7 :(得分:2)

名称的 post 部分不仅来自运算符的物理存在(在操作数之前或操作数之后),而且来自实际更新变量的时间。

后缀增量定义为here

  

[increment(++)运算符,]如果使用postfix,运算符后的运算符(例如,x ++),则   它在递增之前返回值。

因此,它将值返回到连接,然后递增变量。也就是说,在将原始值返回到加法运算之后更新后递增变量。

您的问题的答案在于实现变量何时更新。

运算符优先级有意义,因为仍然首先计算后缀,然后是 添加执行。但是,在将值返回到添加之前,不会更新后缀的变量。因此,结果是" 4242"。