ES规范解读之自增操作符

ES规范解读之自增操作符

原文:https://github.com/kuitos/kuitos.github.io/issues/24
几个月前,不知道什么缘由跟同事讨论了起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;

当我在想怎么去确定这一点时,松波给出了解决方案,用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,有兴趣的同学可以试试用这个方式来验证一下。

顺便抖个机灵,自增操作是非原子性操作,是非线程安全的,多线程环境下共用变量使用自增操作符是会有问题的(前端同学们别急,ES7会为我们带来js多线程编程体验?)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值