JavaScript运算符:递增和递减
JavaScript中的递增和递减运算符都是一元操作符,言外之意就是只能操作一个值的操作符。递增和递减操作符直接借鉴自C语言,各有两种版本:前置型(递增++i,递减--i)和后置型(递增i++,递减i--)。
在JavaScript中,递增(递减)的前置和后置运算符对于初学者都非常容易混淆。我就属于这一类型,这次下定决心把这两者的使用和不同之处了解清楚。如果你和我一样,不仿一起来了解一二。
前置型递增(递减)
前置型递增也称之为前增量(pre-increment)运算符,它对操作数进行增量计算,并返回其计算后的值。这样或许不太好理解,换过一种方式来理解:前增量指的先计算,后赋值。
如果文字不好理解,直接上示例,因为代码也是一种好的阐述方式。假设有一个变量i,其值为1。那么前置递增为++i。
var i = 1;
console.log(i); // => 1
++i;
console.log(i); // => 2
这个示例,前置递增++i操作符把i的值变成了2(也就是1+1)。实际上,执行前置递增++i和执行下面的表达式效果相同:
var i = 1;
i = i + 1;
console.log(i); // => 2
简单点讲,前置型递增就是先自身计算,再赋值给变量:
var i = 1;
var a = ++i; // var i = 1; i = i + 1; a = i;
console.log(a); // => 2
console.log(i); // => 2
其中var a = ++i,实际上做了下面这几个操作:
i = 1;
a = i + 1;
i = i + 1;
a = i;
上面的可能有点简单,来看一个复杂一点的:
var i = 1;
a = (++i) + (++i) + (++i);
最终a的值是多少?把上面的简化为:
(function () {
var i = 1;
var foo = function () {
var j;
j = i + 1;
i = i + 1; // =>2
return j; // => 2
};
var bar = function () {
var m;
m = i + 1; // => 3
i = i + 1; // => 3
return m; // => 3
};
var baz = function () {
var n;
n = i + 1; // => 4
i = i + 1; // => 4
return n; // => 4
};
var a = foo() + bar() + baz(); // 2 + 3 + 4 = 9
return a; // 9
})();
最终a的值是9。
前置递减--i和前置递增++i类似,不同的是先做减法(减1),再赋值。比如:
var i = 6;
a = --i;
console.log(a); // => 5
console.log(i); // => 5
代码中的--i相当于:
var i = 6;
i = i - 1;
a = i - 1;
a = i;
执行前置递增和递减时,变量的值都是在语句被求值以前改变的(返回它递增(减)之后的值)。在计算机科学领域中,这种情况通常被称之为副效应。来看个例子:
var age = 29;
var anotherAge = --age + 2;
console.log(age) // => 28 (age = age - 1)
console.log(anotherAge); // 30 (anotherAge = age - 1 + 2)
这个示列中变量anotherAge的初始值等于变量age的值前置递减(age = age - 1)再加上2。也就是前置--age先做减法操作,age的值变成了28,所以再加上2,其值就是30。
另外在JavaScript运算符中,前置递增(++i)和递减(--i)与执行语句的优先级相同,因此整个语句会从左至右被求值。再来看一个示例:
var foo = 1;
var baz = 20;
var bar = ++foo + baz;
var baf = foo + baz;
console.log(foo); // => 2
console.log(bar); // => 22
console.log(baf); // => 22
在这里,bar等于22是因为foo选加了1之后与baz相加。而baf也等于22是因为相应的加法操作使用了foo加上1之后的值。
需要注意的是,表达式++i并不总和i = i + 1完全一样,++运算符从不进行字符串连接操作,它总是会将操作数转换为数字并增1。如果i是字符串"1",++i的结果是数字2,而i+1是字符串"11"。
var i = "1";
console.log(typeof(i)); // => string
console.log(++i); // => 2
console.log(typeof(++i)); // => number
现来看i+1;
var i = "1";
console.log(typeof(i)); // => string
console.log(i+1); // => "11"
console.log(typeof(i+1)); // => string
后置型递增(递减)
前面也说过了,递增(递减)分前置型和后置型。前置型是++i(--i),后置型不同的是,将++(或--)放置在变量的后面,即i++(或i--)。后置型递增(递减)又称之为后增量(post-increment)运算符。
后置型递增是和前置型递增不同之处是其先赋值,后递增。简单点说,后置型递增是先将自身的值赋值给变量,然后再自增1。来看个例子:
当var a = i++时,其实际上做了下面这样的操作:
i = 1;
j = i;
i = i + 1;
a = j;
对于后置递增运算符,其自身并不会改变语句的结果,因为递增是这条语句的唯一操作。
var i = 1;
console.log(i); // => 1
console.log(i++); // => 1
上面的例子中i++并没有改变值,仍然是1。当然,当语句中还包含其他操作符时,上述区别就会非常明显了。如下面的示例:
var num1 = 2;
var num2 = 22;
var num3 = num1++ + num2; // var n; n = num1; num1 = num1 + 1; num3 = n + num2 = 24
var num4 = num1 + num2; // num1 + num2 = 25
console.log(num1); // => 3
console.log(num3); // => 24
console.log(num4); // => 25
来看一个复杂一点的示例,把前面示例中的前置递增,换成后置递增:
var i = 1;
a = (i++) + (i++) + (i++);
此时的a又是多少呢?按同样的方法,将上面的表达式(i++) + (i++) + (i++)拆解一下:
(function () {
var i = 1;
var foo = function () {
var j;
j = i; // => 1
i = i + 1; // => 2
return j; // => 1
};
var bar = function () {
var m;
m = i; // => 2
i = i + 1; // => 3
return m; // => 2
};
var baz = function () {
var n;
n = i; // =>3
i = i + 1; // => 4
return n;
};
var a = foo() + bar() + baz(); // 1 + 2 + 3 = 6
return a; // 6
})()
a最后的值是6。不过将前置递增和后置递增混合在一起做运算时,事情将会变得更复杂一些,不过按上述的方法去拆解,就不会出错。来看个示例:
var i = 2;
a = (++i) + (i++) + (++i) + (i++);
上面代码中a的值又是多少呢?
(function () {
var i = 2;
var foo = function () {
var j;
j = i + 1; // => 3
i = i + 1; // => 3
return j; // => 3
};
var baz = function () {
var m;
m = i; // => 3
i = i + 1; // => 4
return m; // => 3
}
var bar = function () {
var n;
n = i + 1; // =>5
i = i + 1; // => 5
return n; // => 5
}
var boo = function () {
var l;
l = i; // => 5
i = i + 1; // => 6
return l; // => 5
}
var a = foo() + baz() + bar() + boo(); // 3 + 3 + 5 + 5
return a; // => 16
})();
后置递减(i--)和后置递增是类似的,不同的是,其先赋值,后减1。简单点看个示例:
var i = 2;
var a = i--;
console.log(a); // => 2
console.log(i); // => 1
其中i--就是:
var i = 1;
var m = i;
i = i - 1;
前置递增(递减) VS. 后置递增(递减)
如果你看完了前面两部分内容,到这里的话你对前置递增(递减)和后置递增(递减)之间的区别已有一定的了解。这部分再啰嗦一下两者之间的区别。
- 前置递增:前置递增运算符
++在变量的前面,如++i - 后置递增:后置递增运算符
++在变量的后面,如i++ - 前置递减:前置递减运算符
--在变量的前面,如--i - 后置递减:后置递减运算符
--在变量的后面,如i--
简单回顾两个示例,就拿前置递增和后置递增为例吧,先来看前置递的示例++i:
var i = 1;
console.log(i); // => 1
var a = ++i;
console.log(i); // => 2
console.log(a); // => 2
接下来看后置递增的示例:
var i = 1;
console.log(i); // => 1
var a = i++;
console.log(i); // => 2
console.log(a); // => 1
上面两示例可以看出:
- 前置递增
++i,i先将身的值自增1(相当于i=i+1),再将自增后的值赋值给变量a - 后置递增
i++,i先将自身的值赋值给变量a,然后i再自增1(相当于i = i + 1) - 前置递减
--i,i先将自的值自减1(相当于i = i - 1),再将自减后的值赋值给变量a - 后置递减
i--,i先将自身的值赋值给变量a,然后i再自减1(相当于i = i - 1)
其中原理并不复杂,主要是和JavaScript中运算符优先级有关系:
++作为前置递增时,优先级为15,--作为前置递减时,优先级为15++作为后置递增时,优先级为16,--作为后置递减时,优先级为16=作为赋值运算符时,优先级为3
所以++(或 --)会优先于=而执行。
归纳起来:
前置递增(前置递减)运算符,先计算(自增
1(或自减1)),再赋值,返回操作对象递增(递减)之后的值;后置递增(后置递减)运算符,先赋值,再计算(自增1(或自减1)),返回操作对象递增之前的值。
可以理解成:
++i,增加变量,返回一个新的值i++,增加变量,返回旧的值--i,减少变量,返回一个新的值i--,减少变量,返回旧的值
看个示例:
var a = 5;
var b = 5;
c = ++a;
d = b++;
console.log(a); // => 6
console.log(b); // => 6
console.log(c); // => 6
console.log(d); // => 5
最后为了方便查阅,列表表格
JavaScript自增、自减运算符与表达式,假设i的初始值为6:
| 运算符 | ++i |
--i |
i++ |
i-- |
|---|---|---|---|---|
| 名称 | 前置递增(前增量) | 前置递减(前减量) | 后置增量(后增量) | 后置减量(后减量) |
| 表达式 | ++i |
--i |
i++ |
i-- |
| 描述 | 先自增1,后赋值 |
先自减1,后赋值 |
先赋值,后自增1 |
先赋值,后自减1 |
| 返回 | 返回操作对象递增的值 | 返回操作对象递减的值 | 返回操作对象递增之前的值 | 返回操作对象递减之前的值 |
| 示例 | ++i; |
--i; |
i++; |
i-- |
i的结果 |
7 |
5 |
7 |
5 |
逻辑语句中的递增(递减)
在for循环语句中,常会看到i++、i--、++i和--i。那么像for语句中前置递增(递减)和后置递增(递减)有没有区别呢?
先来看看for循环中的i++和++i:
for(var i = 0; i < 10; i++) {
console.log(i);
}
console.log("-------------- 华丽的分割线 --------------");
for(var i = 0; i < 10; ++i) {
console.log(i);
}
运行结果如下图所示:

从运算的结果上来看,它们的结果是一致的。或许你会感觉有点不对,因为前面讲++i和i++还是有区别的。那么仔细看看他们的运算顺序。
就上面的示例来说,for循环的执行顺序是:
- 进入循环
- 首先是初始化,
var i = 0; - 条件判断
i < 10;,如果条件满足,进入执行语句console.log(i) - 循环结束后,执行
i++(或者++i) - 执行完
i++后跳到第三步,依此3-4-5-3-4-5这样的循环,直到条件不满足为止
把for循环语句块换成:
for(A;B;C) {D}
实际上程序执行的过程是:A-(B-D-C)-(B-D-C)-(B-D-C)...-B这样的一个过程。或许你感觉他们的结果本不相同的,但输出为什么都是一样呢?我们再来回忆一下i++和++i:
先来看:
i++;
其等价于下面的语句:
i = i;
i = i + 1;
结果i增加了1。再来看看:
++i;
其等价于下面的语句:
i = i + 1;
i = i;
从上面的代码来看,不管怎么执行,他们最终都自增了1。那么将其赋值在别的值上呢?如下:
a = i++;
等价于
a = i;
i = i + 1;
而
b = ++i;
其相当于:
i = i + 1;
b = i;
也就是b = i + 1。
如此一来,将前面的示例改动一下:
for (var j = 0, i = 0; j < 10; j) {
j = i++;
console.log("循环" + j + ":" + "i=" + i + ",j=" +j);
}
console.log("------------------- 华丽的分割线 -------------------------");
for (var j = 0, i = 0; j < 10; j) {
j = ++i;
console.log("循环" + j + ":" + "i=" + i + ",j=" +j);
}

上图可以说明一切了吧。除了for循环之外,在JavaScript中还有while和switch等,感兴趣的同学可以跑个测试,看看其结果是否相同。
前置递增(递减)和后置递增(递减)适用场景
不管是前置递增(递减)和后置递增(递减)这四种操作符对任何值都适用,也就是它们不仅适用于整数,还适用于字符串、布尔值、浮点数值和对象。在应用于不同的值时,递增和递减操作符遵循下列规则:
- 在应用于一个包含有效数字字符的字符串时,先将其转换为数字值,再执行加减
1操作。字符串变量变成数值变量。 - 在应用于一个不包含有效数字字符的字符串时,将变量的值设置为
NaN。字符串变量变成数值变量。 - 在应用于布尔值
false时,先将其转换为0再执行加减1的操作。布尔值变量变成数值变量。 - 在应用于布尔值
true时,先将其转换为1再执行加减1的操作。布尔值变量变成数值变量。 - 在应用于浮点数值时,执行加减
1的操作。 - 在应用于对象时,先调用对象的
valueOf()方法以取得一个可供操作的值。然后对该值应用前述规则。如果结果是NaN,则调用toString()方法后再应用前述规则。对象变量变成数值变量。
来看个示例:
var s1 = "2",
s2 = "z",
b1 = false,
b2 = true,
f = 1.1,
o = {
valueOf: function() {
return -1;
}
};
console.log(s1++); // => 3
console.log(s2++); // => NaN
console.log(b1++); // => 0
console.log(b2++); // => 1
console.log(f++); // => 1.1
console.log(o++); // => -1
其他三种结果,可以将上面的代码简单更改一下,然后跑一下测试,就能看到对应的结果。这里就不再做相应的测试了。
总结
这篇文章主要介绍了JavaScript中前置递增(递减)和后置递增(递减)的使用,以及它们之前的不同之处。对于初学者而言,++i(--i)和i++(i--)经常会混淆,不知道它们之间的具体区别。经过这次,对它们之间的不同之处有了一个基本的了解。最后,希望这篇文章对您有所帮助。
如需转载,烦请注明出处:http://www.w3cplus.com/javascript/javascript-increment-and-decrement-operatorssass.html




