Javascript 简单易混淆的循环和变量工作

Javascript 简单易混淆的循环和变量工作,javascript,Javascript,在这个问题中,我要问以下代码段是如何工作的,因为它涉及到变量的奇怪用法: while (+(+i--)!=0) { i-=i++; } console.log(i); i-=i++的意思与i=i-i类似;i++(如果将-=显式化) 以类似的方式,您可以通过 将while(foo(i-){…}转换为while(foo(i)){i-;…}i-(您需要将其放在循环体中和循环后,因为在最后,条件将为false,循环体将不会执行,但在while循环后执行将继续)。这就是sooo wierd!(我

在这个问题中,我要问以下代码段是如何工作的,因为它涉及到变量的奇怪用法:

while (+(+i--)!=0)
{
    i-=i++;
}
console.log(i);

i-=i++
的意思与
i=i-i类似;i++
(如果将
-=
显式化)

以类似的方式,您可以通过 将
while(foo(i-){…}
转换为
while(foo(i)){i-;…}i-(您需要将其放在循环体中和循环后,因为在最后,条件将为false,循环体将不会执行,但在while循环后执行将继续)。

这就是sooo wierd!(我喜欢)

首先,您可以忘记
+(++
部分,这就像说
1+(+1)=2

i--
表示
i=i-1
。在
while
条件下,测试
i--
是否与
0
不同。注:测试在
i!=0,然后更改
i
的值。如果您想在测试之前更改它的值,应该使用
--i

至于
i-=i++
,说
i=0
是一种非常愚蠢的方式。您必须从右到左阅读它:
i=i+1
,然后
i=i-i
1(无论
i
的值是多少,您都会得到
0

更简单的等效代码段:

while (i-- != 0) {
  i = 0;
}
console.log(i);

1
a-=b
意味着
a=a-b

有趣的问题……您已经将其标记为Java、JavaScript和C——请注意,虽然这些语言具有相同的语法,但这个问题涉及到非常微妙的语义,可能(我不确定)不同语言之间存在差异

让我们把它分解一下:

+(+i--)
--
后缀减量运算符的约束最为紧密。因此这相当于
+(+(i-)
。因此这相当于
+(+i)
(即
i
)的值,但它也会在获取值后递减
i
。它会将值与0进行比较,以查看循环是否应继续。因此,
while(+(+i-)!=0)
相当于以下内容:

while (i-- != 0)
请注意,它还在循环结束时执行
i--

在循环内部,我相信您有一些未定义的行为,至少在C中是这样,因为您在右边引用了
I
,在左边也更新了
I
——我相信C并没有定义在哪个顺序中进行更新。所以您的结果可能会因编译器而异。Java至少是一致的,所以我将给出Java答案。
i-=i++
相当于
i=i-i++
,这相当于从表达式中读取所有值,计算表达式的结果,应用后增量,然后将结果赋回。即:

int t = i - i;    // Calculate the result of the expression "i - i++"
i++;              // Post-increment i
i = t;            // Store the result back
显然,这与写入
i=0
相同。因此循环体将i设置为0

因此,循环只执行一次,将i设置为0。然后,它在下一个while循环中再次递减
i
,但检查失败,因为
i
(递减之前)==0

因此,不管
i
的初始值是多少,最终答案都是
-1

要将所有这些放在一起并编写等效程序:

while (i-- != 0)
{
    int t = i - i;
    i++;
    i = t;
}
console.log(i);
当我在Java和JavaScript中尝试时,这就是我得到的。对于GCC(C编译器),只有当
I
开始时为0时,它才会给出-1。如果
I
开始时为其他任何东西,它就会进入无限循环

这是因为在GCC(不一定是所有C编译器)中,
i-=i++
具有不同的含义:它首先将存储返回到
i
,然后执行后期增量。因此,它相当于:

int t = i - i;    // Calculate the result of the expression "i - i++"
i = t;            // Store the result back
i++;              // Post-increment i
这相当于写入
i=1
。因此,在第一次迭代中,它将
i
设置为1,然后在循环中,它检查
i==0
,而它不是,因此它再次循环,总是将
i
设置为1。这永远不会终止,但对于
i
开始为0的特殊情况,它将将始终终止循环并递减
i
(因此您得到
-1

另一个C编译器可能会选择像Java一样运行,这表明您永远不应该编写同时赋值和后加同一个变量的代码:您永远不知道会发生什么


编辑:我试图对
循环使用
;这是不等价的。返回到while循环。

while条件求值是基于运算符优先级进行的。我使用了显式大括号来帮助理解求值:

(+(+(i-)!=0),这相当于使用(i-!=0),因为“+”只是一元运算符

表达式i-=i++;相当于i=i-i++;其中LHS表达式从左到右求值

i = 4;
while (+(+i--)!=0)  //here i would be decremented once to 3.
{     
     i-=i++; // here i = 3 - 3 = 0; even though i has been incremented by 1 its value is set to 0 with this assignment
} 

这很简单。我认为这样编写代码的唯一原因是一个叫做“代码对象”或“代码混淆”的概念。这种方式使代码更难阅读和调试,从而可以防止对代码进行反向工程:-)

什么是
I
的初始值?这必须是未定义的行为。在C中,我认为I-=I++是未定义的行为,但我不确定---:)在C中,它是未定义的行为。在Java中,没有未定义的行为!这很奇怪,但它确实有明确的含义。在JavaScript中,我不太确定。有关详细信息,请参见我的答案。@Oltarus我想我们应该只描述它的作用,而不管
I
的初始值是什么。(你可以想象它是一个以
i
为参数的函数——函数做什么呢?)很好的答案——几乎是正确的,但这取决于语言(这对于Java是正确的。对于C,它是未定义的,对于JavaScript,我不知道)。@mgiuca-true。我只使用Java进行了测试。剩下的是@Delma