A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

nthsky

初级黑马

  • 黑马币:39

  • 帖子:11

  • 精华:0

本帖最后由 nthsky 于 2016-9-21 00:38 编辑

看玄真道长的视频中有人提问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中的运算逻辑似乎并不完全一致
首先,前缀++本次运算中就进行自加以及逗号、分号代表本次运算结束的逻辑和引文中描述的是一致的,感兴趣的可以自己写几个数组之类的进行观察。
然后,用JS对例1进行验算,如例2
[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,自加在*后才进行执行,使*后的a4,然后*后的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论坛上的问题)

10 个回复

倒序浏览
奔跑地小少女 来自手机 中级黑马 2016-9-20 23:08:29
沙发
好帖必顶!
回复 使用道具 举报
楼主好认真,这是我的一点看法:
a = 3
a+=a+=12
a+=12           => a = a+12
a+=a+=12    => a = a + a +12
加法的结合律
回复 使用道具 举报
花开 发表于 2016-9-20 23:40
楼主好认真,这是我的一点看法:
a = 3
a+=a+=12

我写的是a+=a+=a啊,然后a输出为9.
+=也能结合一般人感觉不会直接这么想把
反正我一开始的想法是a+=a然后a就变6了,再a+=a,a就变12了。。
可是js中并不是这样
回复 使用道具 举报
nthsky 发表于 2016-9-20 23:57
我写的是a+=a+=a啊,然后a输出为9.
+=也能结合一般人感觉不会直接这么想把
反正我一开始的想法是a+=a然后a ...

我是这么理解的: 全把 += 换成 普通的  a = a+ a , + 比 = 优先级高
a = a +a + a
回复 使用道具 举报
回复 使用道具 举报
nthsky 初级黑马 2016-9-21 00:13:40
7#
花开 发表于 2016-9-21 00:02
我是这么理解的: 全把 += 换成 普通的  a = a+ a , + 比 = 优先级高
a = a +a + a
...

嗯,反正知道了js中这个鬼东西是这么算的。。
关于前后缀++ --估计你也懂了。。就是各人理解方法不同
回复 使用道具 举报
@柳柳桑,这个帖子必须给技术分的呀
回复 使用道具 举报
此帖必火,楼主总结的不错
回复 使用道具 举报
楼主讲得真细致
回复 使用道具 举报
今天回头看了看笔记,看了看基础视频,想起这个问题,又想起很久之前看到的贴吧上的一个帖子专门写了自加自减的问题,找了半天没找到偶然找到黑马的这个贴吧,不禁想到当初被这个问题整懵逼的时候还是以去黑马为目标,不曾想转眼已经过去两年,感慨良多,只能说加油
把那个贴吧的帖子发来,楼主如果看到而且有兴趣的话,可以再研究
http://tieba.baidu.com/p/2981878409?see_lz=1
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马