资讯专栏INFORMATION COLUMN

ES规范解读之自增操作符

junnplus / 2924人阅读

摘要:对于这种疑问,我们只能求助给出官方解释后自增操作符从上的算法描述,我们能够清晰的得知,后自增操作符是先自增赋值,然后返回自增前的值,这样的一个顺序。

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:

Evaluate LeftHandSideExpression.

Call GetValue(Result(1)).

Call ToNumber(Result(2)).

Add the value 1 to Result(3), using the same rules as for the + operator (see 11.6.3).

Call PutValue(Result(1), Result(4)).

Return Result(3).

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

i = i + 1; return iBeforeIncrease = 0;

i = iBeforeIncrease;

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

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多线程编程体验?)。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/86003.html

相关文章

  • lodash源码分析之baseFindIndex中的运算符优先级

    摘要:从表中可以看到,比较运算符的优先级为,而三元表达式条件运算符的优化级为,因此可以确定比较运算符的优先级要比三元表达式的要高,循环条件其实等价于第二种写法。从上表中也可以看出前缀自增比比较运算符的优化级要高。 我悟出权力本来就是不讲理的——蟑螂就是海米;也悟出要造反,内心必须强大到足以承受任何后果才行。——北岛《城门开》 本文为读 lodash 源码的第十篇,后续文章会更新到这个仓库中...

    Meathill 评论0 收藏0
  • 从 ++[[]][+[]]+[+[]]==10? 深入浅出弱类型 JS 的隐式转换

    摘要:与此相对,强类型语言的类型之间不一定有隐式转换。三为什么是弱类型弱类型相对于强类型来说类型检查更不严格,比如说允许变量类型的隐式转换,允许强制类型转换等等。在中,加性运算符有大量的特殊行为。 从++[[]][+[]]+[+[]]==10?深入浅出弱类型JS的隐式转换 本文纯属原创? 如有雷同? 纯属抄袭? 不甚荣幸! 欢迎转载! 原文收录在【我的GitHub博客】,觉得本文写的不算烂的...

    miya 评论0 收藏0
  • ES规范解读之赋值作符&属性访问器

    摘要:那么什么是基础对象组件呢,举两个例子我们再来看看属性访问器,就是括号操作符及点号操作符都做了什么属性访问器也就是说括号跟点号对解释器而言是一样的。 ES规范解读之赋值操作符&属性访问器 原文:https://github.com/kuitos/kuitos.github.io/issues/24事情起源于某天某妹子同事在看angular文档中关于Scope的说明Understandin...

    funnyZhang 评论0 收藏0
  • ECMAScript 2018 标准导读

    摘要:标准对象,语义由本规范定义的对象。三个冒号作为分隔符分割数字字符串文法的产生式。所有因为带来的问题,基本上是占着茅坑不拉屎的行为导致。以数组测试操作为例,标准中的描述如下相对于来说,规范中增加了对的处理。 前言 本文是对《ECMAScript 2018 Language Specification》的解读。本文是对标准的概述性导读,不是对 ES2018特性的详细描述,也不会针对某个技术...

    MiracleWong 评论0 收藏0
  • JavaScript深入之从ECMAScript规范解读this

    摘要:深入系列第六篇,本篇我们追根溯源,从规范解读在函数调用时到底是如何确定的。因为我们要从规范开始讲起。规范类型包括和。下一篇文章深入之执行上下文深入系列深入系列目录地址。如果有错误或者不严谨的地方,请务必给予指正,十分感谢。 JavaScript深入系列第六篇,本篇我们追根溯源,从 ECMAScript5 规范解读 this 在函数调用时到底是如何确定的。 前言 在《JavaScript...

    TIGERB 评论0 收藏0

发表评论

0条评论

junnplus

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<