对于刚开始接触前端开发的朋友们来说,可能地一个令人苦恼的问题是关于运算符 ++ 的计算,特别是它还有前置与后置的区别。当它们和一堆运算在一起的时候,常常令人头晕目眩!

我经常性地称它是一个***难人的问题,因为它本身所发生的操作又是十分的简单——加 1。是的,++ 运算符的唯一计算操作就是给它的操作数加 1。然而,它到底是怎么加的 1 呢?就我而言,我一直都觉得这很神奇,它应该是使用了某种魔法吧!

拨开层层迷雾,在你看见了它的庐山真面目后,你又会惊讶于它是如此的简单纯粹。这一切,都要从最基本的概念——表达式说起。

什么是表达式?表达式是对一个变量或值的引用,或是一组值和变量与运算符的组合。

举例来说,像 1、2 这样的字面值就是一个表达式,尽管它没有多大意义。我们更经常接触的表达式是像 1 + 1 这样的,值与运算符的组合。

表达式的本质是值。分两点来说,一是我们使用表达式的真正目的是要取得它背后的值;二是一个表达式总是会运算并返回一个值。比如,1 + 1 和 2 是等价的,在使用 1 + 1 这个表达式的地方,我们都可以把它换成值 2。这在计算机中之所以成立,是因为 1 + 1 这个表达式它总是会运算并返回值 2。试想一下,如果表达式 1 + 1 没有被计算,它怎么能和值 2 相等呢?

所以,1 + 1 和 2 是等价的准确说法,应该是表达式 1 + 1 的返回值和值 2 是等价的,它们是相等的。尽管前者的概念是表达式,后者的概念是值。

我们再来看一个例子:

let a = 1;
let b = a + 1;

请问这里的变量 b 等于多少?要正确的回答这个问题,你得知道在 a + 1 这个表达式中变量 a 也是一个表达式。所以,我们首先得知道表达式 a 的值是多少,然后将它和 1 相加。表达式和表达式可以通过运算符组合在一起,得到一个新值。这里,表达式 a 的值就是变量 a 引用的值 1。

再来看一个例子:

let a = 1;
let b = (a = 2) + 1;

请问这里的变量 b 又等于多少呢?或者说表达式 (a = 2) + 1 的值是多少?你可能发现了,关键点是要知道表达式 a = 2 的值是多少。

这里就引出了表达式的另一个重要内涵——副作用。表达式的副作用是指表达式在返回值的过程中对别处的值也产生了影响。赋值表达式的副作用就是将某个值赋给了变量,或者说它更换了变量中的值。在 (a = 2) + 1 中,赋值表达式 a = 2 会先给变量 a 赋值 2,然后返回这个变量的值。所以,这里表达式 a = 2 的返回值便就是 2。

有了上面这些概念后,你对前 ++ 和后 ++ 的区别就会有着很好的理解。

这里顺带补充一点,++ 运算符只能和变量一起使用。也就是说,++ 运算符的操作数必须是一个变量,因为它需要一个容器(变量)来承接它的副作用。

前 ++ 和后 ++ 的关键区别就在于它们对操作数执行加 1 的操作的时机点不同。前 ++ 是在返回表达式值之前就对操作数进行了加 1 的运算,后 ++ 则是在返回表达式值之后再对操作数执行加 1 的操作。

举例来说:

let a = 1;
let b = (a++) + 1 + a + (++a) + a + 1;

请问这里的变量 b 又会是等于多少呢?关键点就在 a++ 和 ++a 这两个表达式的值是多少!

a++ 是一个后 ++ 表达式,后 ++ 的副作用发生在它返回表达式值之后。所以,这里 a++ 会先返回表达式 a 的值。所以,这里表达式 a++ 的返回值就是变量 a 的直接引用值 1。

那么紧接在 a++ 后面的那个变量 a 又会是等于多少呢?是 2。因为,前面的 ++ 操作已经给 a 加了 1。所以,这里表达式  (a++) + 1 + a  等价于 1 + 1 + 2。

注意体会这里的操作,这个地方发生且仅发生了两件事:第一件事是返回变量 a 引用的值,第二件事是给变量 a 执行加 1 的运算。这就是为什么后面的 a 会是 2 的原因了,因为这时的 a 已经被加了 1。

++a 是一个前 ++ 表达式,前 ++ 的副作用发生在它返回表达式值之前。也就是说,前 ++ 表达式得到的值是 ++ 运算符执行计算后的结果值。所以,这里表达式 ++a 的值是 3。

所以,这里表达式 (a++) + 1 + a + (++a) + a + 1 等价于 1 + 1 + 2 + 3 + 3 + 1,最终计算结果为 11。

最后,和 ++ 对应的 -- 运算符的运算规则和 ++ 是完全一致的,只不过它的操作是对操作数执行减 1 的运算。

准确理解 JS 的 ++ 运算符的更多相关文章

  1. 从一个简单例子来理解js引用类型指针的工作方式

    <script> var a = {n:1}; var b = a; a.x = a = {n:2}; console.log(a.x);// --> undefined conso ...

  2. js对象详解(JavaScript对象深度剖析,深度理解js对象)

    js对象详解(JavaScript对象深度剖析,深度理解js对象) 这算是酝酿很久的一篇文章了. JavaScript作为一个基于对象(没有类的概念)的语言,从入门到精通到放弃一直会被对象这个问题围绕 ...

  3. 好程序员web前端分享如何理解JS的单线程

    好程序员web前端分享如何理解JS单线程,JS本质是单线程的.也就是说,它并不能像JAVA语言那样,两个线程并发执行. 但我们平时看到的JS,分明是可以同时运作很多任务的,这又是怎么回事呢? 首先,J ...

  4. 10分钟理解JS引擎的执行机制

    首先,请牢记2点: (1) JS是单线程语言 (2) JS的Event Loop是JS的执行机制.深入了解JS的执行,就等于深入了解JS里的event loop 1.灵魂三问 (1) JS为什么是单线 ...

  5. 深入理解 JS 引擎执行机制(同步执行、异步执行以及同步中的异步执行)

    首先明确两点: 1.JS 执行机制是单线程. 2.JS的Event loop是JS的执行机制,深入了解Event loop,就等于深入了解JS引擎的执行. 单线程执行带来什么问题? 在JS执行中都是单 ...

  6. 深入理解JS this,作用域

    深入理解JS this 阮一峰博客链接http://www.ruanyifeng.com/blog/2010/04/using_this_keyword_in_javascript.html this ...

  7. 【学习笔记】深入理解js原型和闭包(5)——instanceof

    又介绍一个老朋友——instanceof. 对于值类型,你可以通过typeof判断,string/number/boolean都很清楚,但是typeof在判断到引用类型的时候,返回值只有object/ ...

  8. 【学习笔记】深入理解js原型和闭包(1)—— 一切都是对象

    “一切都是对象”这句话的重点在于如何去理解“对象”这个概念. ——当然,也不是所有的都是对象,值类型就不是对象. 首先咱们还是先看看javascript中一个常用的运算符——typeof.typeof ...

  9. 理解JS引擎的执行机制

    首先,请牢记2点: (1) JS是单线程语言 (2) JS的Event Loop是JS的执行机制.深入了解JS的执行,就等于深入了解JS里的event loop 1.灵魂三问 : JS为什么是单线程的 ...

  10. 深入理解JS引擎的执行机制

    深入理解JS引擎的执行机制 1.灵魂三问 : JS为什么是单线程的? 为什么需要异步? 单线程又是如何实现异步的呢? 2.JS中的event loop(1) 3.JS中的event loop(2) 4 ...

随机推荐

  1. weixueyuan-Nginx集群9

    https://www.weixueyuan.net/nginx/colony/ LVS(Linux虚拟服务器)简介 LVS(Linux Virtual Server)是一个开源的负载均衡项目,是国内 ...

  2. Practical Secure Aggregation for Privacy-Preserving Machine Learning

    1 介绍 本文是谷歌团队发在CCS2017上的文章,旨在解决联邦学习中安全聚合的问题. 安全聚合:多方参与者将信息传递给聚合者,聚合者除了知道这个信息的总和不能知道任何一个特定参与者的信息. 在这篇文 ...

  3. VulNyx - Responder靶场

    靶机ip 192.168.200.9 先nmap 扫描全端口 这个22端口不知道有没有开 被过滤了 我们 收集一下靶机的ipv6地址 nmap用ipv6地址扫他的端口就能绕过 他的端口过滤 ping6 ...

  4. 深入剖析Base64加解密中遇到的坑点

    前言 最近开发过程中遇到了关于使用base64加密传输遇到的神奇问题.需求就是用户的id在链接上露出时需要加密处理,于是后端把下发的用户id改成了base64加密处理后下发了,前端只需要把加密后的用户 ...

  5. Flink On Yarn的两种部署模式

    一.内存Job管理模式yarn-per-job 使用介绍:常用的模式 二.内存集中管理模式yarn-session 使用介绍:当作业很少并且都较小,能快速执行完成时,可以使用.否则一般不会使用该模式 ...

  6. Luogu P8112 [Cnoi2021] 符文破译 题解 [ 蓝 ] [ KMP ] [ 线性 dp ] [ 决策单调性 dp ]

    符文破译:KMP + dp 的好题. 暴力 dp 不难打出一个暴力 dp:设计 \(dp_i\) 表示当前前 \(i\) 位全部完成了匹配,所需的最小分割数. 转移也是简单的,我们在 KMP 的过程中 ...

  7. [BZOJ4833] 最小公倍佩尔数 题解

    在这篇题解中,我会将各个部分的证明分成不同的推导过程,以达到逐一击破的效果. 引理 1:\(f(n)=2f(n-1)+f(n-2)\) 我的证明挺繁琐的,过程如下: \[(1+\sqrt 2)^{n- ...

  8. mysql常用优化

    SQL优化是一个分析,优化,再分析,再优化的过程.站在执行计划的角度来说,我们这个过程,就是在不断的减少rows的数量. 1.建索引 2.减少表之间的关联 3.优化 sql,尽量让 sql 很快定位数 ...

  9. 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!

    引子:那个让运维集体加班的夜晚 "凡哥!线上服务响应时间飙到10秒了!"凌晨1点,实习生小李的语音带着哭腔. 监控大屏上,JVM堆内存曲线像坐了火箭--刚扩容的16G内存,30分钟 ...

  10. ZLMediaKit: 快速入门

    目录 ZLMediaKit是什么 编译 安装依赖库 构建项目 问题处理 问题1: srtp 未找到, WebRTC 相关功能打开失败 问题2:依赖库问题 安装 配置和运行 问题处理 问题1: 无权限监 ...