Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ES规范解读之自增操作符 #26

Open
kuitos opened this issue Aug 31, 2015 · 1 comment
Open

ES规范解读之自增操作符 #26

kuitos opened this issue Aug 31, 2015 · 1 comment

Comments

@kuitos
Copy link
Owner

kuitos commented Aug 31, 2015

ES规范解读之自增操作符

几个月前,不知道什么缘由跟xx同学讨论了起js里自增操作符(i++)的问题,现将前因后果整理出来,传于世人😂

事情起源于这样一段代码

var i = 0;
i = i++;
console.log(i);

来,都来说说答案是啥?
结果是0
换一种形式,或许大家不会有多少疑问

var i = 0;
var a = i++;
console.log(a); // 0

没错,这也是我们初学自增操作符的经典例子,对这结果还有疑问请自觉面壁。。。
遥想当年学习自增操作符的口诀大致是,i++ 是先用后自增,++i 是先自增再用
那么按照这个思路,上面的代码解析流程应该是这样的

var i =0;
i = i;
i = i + 1;

可惜结果并不是这样的
按照犀牛书上的描述,后增量(post increment)操作符的特点是

它对操作数进行增量计算,但返回未作增量计算的(unincremented)值。

但是书上并没有告诉我们,先做增量计算再返回之前的值,还是返回之前的值再做增量计算。
对于这种疑问,我们只能求助ecmascript给出官方解释:

Postfix Increment Operator(后自增操作符)

The production PostfixExpression : LeftHandSideExpression [no LineTerminator here] ++ is evaluated as follows:

  1. Evaluate LeftHandSideExpression.
  2. Call GetValue(Result(1)).
  3. Call ToNumber(Result(2)).
  4. Add the value 1 to Result(3), using the same rules as for the + operator (see 11.6.3).
  5. Call PutValue(Result(1), Result(4)).
  6. Return Result(3).

从es上的算法描述,我们能够清晰的得知,后自增操作符是先自增赋值,然后返回自增前的值,这样的一个顺序。
到这里还不算完。
既然i=i++这种操作最后i还是为原始值,也就是这段代码不会有任何实际意义,那么js引擎有没有可能针对性的做优化,从而避免不必要的自增运算?(如果你用的是IDE,IDE会提示你这是一段无用的代码)
也就是说,我们如何确定,执行引擎一定做了两步操作:

  1. i = i + 1; return iBeforeIncrease = 0;
  2. i = iBeforeIncrease;

还是执行引擎可能会针对性的优化,只做一步操作:

  1. i = iBeforeIncrease;

当我在想怎么去确定这一点时,xx给出了解决方案,用Object.observe()方法啊!!(该方法是ES7提案中的新api,不过chrome早早的实现了)

var obj = {i:0};
Object.observe(obj, function(changes){
    console.log(changes);
});
obj.i = obj.i++;

代码放到chrome中跑一下,可以看到,改变触发了两次,也就是i做了两次修改操作
另外firefox中也提供了一个类似的api,Object.prototype.watch,有兴趣的同学可以试试用这个方式来验证一下。

顺便抖个机灵,自增操作是非原子性操作,是非线程安全的,多线程环境下共用变量使用自增操作符是会有问题的。

@codezyc
Copy link

codezyc commented Sep 24, 2015

好文,学习啦。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants