看玄真道长的视频中有人提问b=a+++a要怎么进行计算,一时间看不透,我是一个比较较真的人,于是,我不禁想深入研究一下a++和++a,了解一下其中的运算逻辑。以下是我研究的过程(文中都是个人的研究过程,并非科班生,知识浅薄,难免有纰漏和错误,欢迎指正。还有,文中的这些运算以后写程序时基本用不到,也避免用到。仅做探讨)。
通过JS的初步学习,我们知道了b=a++和b=++a的区别,不妨令a=5
前者是先赋值,再自加,即b=a;a=a+1; //结果b=5,a=6
后者是先自加,再赋值,即a=a+1;b=a; //结果a=6,b=6
通过百度看到这样一篇帖子《彻底搞清C/C++中a++与++a的区别》,下面摘自原贴(这一部分C语言的东西有待商榷,我自己没尝试过):
(1) 如果用前缀运算符对一个变量增1(减1),则在将该变量增1(减1)后,用新值在表达式中进行其他的运算。
(2) 如果用后缀运算符对一个变量增1(减1),则用该变量的原值在表达式中进行其他的运算后,再将改变量增1(减1)。
这里就有一个问题,对于后缀运算,“用该变量的原值在表达式中进行其他的运算后”该如何理解,也就是说啥时候才算表达式运算完啦。
下面某些摘自《C语言深度解剖》:
i++在遇到每个逗号,分号后,才认为本计算单位已经结束,i这时候自加。
这里有个例1:
[C] 纯文本查看 复制代码
int a=3;
a+=a+=a++*a--;
按照上述规则,计算过程如下:
先算 a++*a-- 由于没有到下一步,所以为3*3=9
再 a+=a++*a-- 即a+=9 => a=a+9=3+9=12
然后 a+=a a=a+12=12+12=24
最后 计算后缀++的第二步自加和后缀—中的第二步自减运算,正好相抵
所以最终a=24;
然而,我用javascript进行了验算,发现js中的运算逻辑似乎并不完全一致
首先,前缀++本次运算中就进行自加以及逗号、分号代表本次运算结束的逻辑和引文中描述的是一致的,感兴趣的可以自己写几个数组之类的进行观察。
[JavaScript] 纯文本查看 复制代码
var a = 3;
a+=a+=a++*a--;
document.write(a);//例2 结果为18
输出的结果为18,和例1显然不同,直接看不出其中的运算方法,下面便对其中的运算逻辑进行尝试
由于++a 和--a在本步运算中就进行自加自减,比较好考虑,所以引出例3
[JavaScript] 纯文本查看 复制代码
var a = 3;
a+=a+=++a*--a;
document.write(a);//例3 结果为18
输出的结果为18,按引文中的规则,前缀++和--在本步中进行自加自减,即++a为4,--a又返回3。++a*--a等于12
即a+=a+=12结果为18,从而推测+=赋值号并不是从右往左逐步赋值,赋值号左边依然是初始值。
通过例4进行验算
[JavaScript] 纯文本查看 复制代码
var a = 3;
a+=a+=a;
document.write(a);//例4 结果为9
输出结果为9 =>推出 js中赋值符号并不是从右往左依次赋值,而是赋值号左边依然用初始值代入,以下不再考虑+=运算
再回到例2,即a++*a--的值也为18-3-3=12
起初猜测是不是JS中a++和a--在本运算式中就进行了自加自减,即a++中a进行了自加等于4,a--又进行了自减等于3,相乘等于12。
但是按照这样的逻辑,b=a++;先赋值再自加就无法解释
于是,想到了例5,否定了以上的运算逻辑,如下:
[JavaScript] 纯文本查看 复制代码
var a = 3;
var b;
b = a++*a++;
document.write(a+”,”+b);//例5 b输出为12,a输出为5
如果按上面的想法在本步中后缀++都进行了自加,显然b输出为4*5=20。
然而b输出结果为12,a输出为5,不得不重新考虑++后缀的运算方法。
经过推敲,综合前文中提到的a++在进行其他运算后进行自加1,符合情理的情况只有3*4,即*号也代表本次计算已经结束, 前一个a++为3,自加在*后才进行执行,使*后的a为4,然后*后的a++后缀++在分号后即下一行的输出中才执行,输出为5。所以b等于3*4,a最后输出为5,要搞清后缀++在何时执行。
再一次返回例(2)进行验算,a+=a+=a++*a--
a++本身为3,然后在*后进行自加,也就是a--的a为4,然后a--的自减被赋值号给覆盖了,所以为a=3+3+3*4。结果正确,逻辑也符合了。
之后,我又对a++ a-- ++a --a进行了其他的综合运算,结果也都符合。证明我最后的猜测是正确的。
既然*号代表本次运算结束,我又对+ - * / 都进行了尝试,结果都是下一次运算的标志。
再然后,我对其他运算符进行尝试,如
[JavaScript] 纯文本查看 复制代码
var a = 3;
if(a++%(a-1)==0){
document.write(true)
}else{
document.write(false)
}//结果为true
验证取余号%也符合条件;
[JavaScript] 纯文本查看 复制代码
var a = 3;
if(a++<a){
document.write(true)
}else{
document.write(false)
}
var a = 3;
if(a++==(a-1)){
document.write(true)
}else{
document.write(false)
}
验证了比较运算符也是;
[JavaScript] 纯文本查看 复制代码
var a = 3;
if(a++&&a==4){
document.write(true)
}else{
document.write(false)
}
验证了逻辑运算符也符合;
最后,再回到文章开头的引子b=a+++a;
涉及到一个名词叫“贪心法”,符号的贪心法是这样的:
编译器将程序分解成符号的方法:从左到右一个字符一个字符的输入,如果该字符可能组成一个符号,那么在读入下一个字符,判断输入的两个字符组成的字符串是否可能是一个符号的组成部分,再重复上面的操作。
有兴趣的可以自己查询了解一下,我也说不清
所以a+++a就理解为(a++)+a所以var a=3时,b输出为3+4=7,a输出为4;
最后对本文关于js中a++ 和++a的运算作下总结
1.关于++ --
(1)如果用前缀运算符对一个变量增1(减1),则在将该变量增1(减1)后,用新值在表达式中进行其他的运算。
(2)如果用后缀运算符对一个变量增1(减1),则用该变量的原值在表达式中进行其他的运算后,再将改变量增 1(减1)。
(3)对“进行其他的运算”的理解:只要是后缀运算符之后出现了任意运算符或者","、";",都属于进行了其他运算。
我也这么理解:后缀++的自加运算比其他运算符要低。
2.关于a+=a+=a++;
js中的运算按照运算优先级表进行从左至右运算,如果一行运算式左边有多个赋值号(如+=),赋值号左侧的变量按运算式执行之前的初始值代入。赋值运算会覆盖掉最后的自加(减)运算。
3.关于a+++a
编译器将程序分解成符号的方法:从左到右一个字符一个字符的输入,如果该字符可能组成一个符号,那么在读入下一个字符,判断输入的两个字符组成的字符串是否可能是一个符号的组成部分,再重复上面的操作。a+++a即(a++)+a;
再来道题:
[JavaScript] 纯文本查看 复制代码
var a = 3;var b = 2;
if(a++&&a+++a==9){
var b=a+=a+++a;
}else{
var b = a;
}
document.write("a为"+a+"<br>b为"+b)
最后输出a为16 b为16,你做对了吗
写在最后:这篇文章前前后后拖了好几天,虽然文章中的这些运算基本不用用到,甚至要去避免,但是探讨的过程还是快乐的,把我的探讨过程分享给大家,希望大家学习愉快。
还有,文章快写完了才发现还有一篇和我有类似疑问的,第一个回答的非常不错,也很专业,从编译器层级分析了这个计算,分享给大家:
《C语言 关于b=a+++a++运算问题?》-----(貌似分享不了外链。。大家百度下吧,一个segmentfault论坛上的问题)