引子
本文讲述了 ECMA-262 中可用于操作数据值的操作符之一元操作符;
ECMAScript 中的操作符是独特的,因为它们可用于各种值,包括字符串、数值、布尔值,甚至还有对象;在应用给对象时,操作符通常会调用 valueOf()
或 toString()
方法来取得可以计算的值。
一元操作符
只操作一个值的操作符叫一元操作符(unary operator)是 ECMAScript中最简单的操作符。
递增与递减操作符
有两个版本,分别是前缀版(位于操作的变量前面)和后缀版(位于要操作的变量后面);
前缀版操作符
前缀递增操作符会给数值加 1,把两个加号(++)放到变量前头即可,如下所示:
let age = 29;
++age; // 等同于 age = age + 1
复制代码
通过前缀递增操作符简化语法把 age 的值变成了 30(给之前的值 29 加 1),下面我们来看递减:
使用前缀递减操作符,只要把两个减号(–)放到变量前头即可,如下所示:
let age = 29;
--age; // 等同于 age = age - 1;
复制代码
执行操作后,变量 age 的值变成了 28(从 29 减 1)
小知识
无论使用前缀递增还是前缀递减操作符,变量的值都会在语句被求值之前改变;如下所示:
let age = 29;
let anotherAge = --age + 2;
console.log(age); // 28
console.log(anotherAge); // 30
复制代码
在这个例子中,变量 anotherAge
以 age 减 1 后的值再加 2 进行初始化,因为递减操作先发生,所以 age 的值先变成 28,然后再加 2,结果是 30。
前缀递增和递减在语句中的优先级是相等的,因此会从左到右依次求值;如下所示:
let num1 = 2;
let num2 = 20;
let num3 = --num1 + num2;
let num4 = num1 + num2;
console.log(num3); // 21
console.log(num4); // 21
console.log(num1); // 1
复制代码
后缀版操作符
递增和递减的后缀版语法一样(分别是++和–),只不过要放在变量后面;后缀版与前缀版的主要区别在于,后缀版递增和递减在语句被求值后才发生。在某些情况下,这种差异没什么影响,比如:
let age = 29;
age++;
复制代码
把递增操作符放到变量后面不会改变语句执行的结果,因为递增是唯一的操作;可是,在跟其他操作混合时,差异就会变明显,比如:
let num1 = 2;
let num2 = 20;
let num3 = num1-- + num2; // num3: 22
let num4 = num1 + num2; // num4: 21
复制代码
这个例子跟前面的那个一样,只是把前缀递减改成了后缀递减,区别很明显;在使用前缀版的例子中,num3
和 num4
的值都是 21;而在这个例子中,num3
的值是 22,num4
的值是 21;这里的不同之处在于,计算 num3
时使用的是 num1
的原始值(2),而计算 num4
时使用的是 num1
递减后的值(1)。
递增递减规则
这 4 个操作符可以作用于任何值,意思是不限于整数——字符串、布尔值、浮点值,甚至对象都可以。
递增和递减操作符遵循如下规则:
- 对于字符串,如果是有效的数值形式,则转换为数值再应用改变;变量类型从字符串变成数值。
- 对于字符串,如果不是有效的数值形式,则将变量的值设置为 NaN ;变量类型从字符串变成数值。
- 对于布尔值,如果是 false,则转换为 0 再应用改变;变量类型从布尔值变成数值。
- 对于布尔值,如果是 true,则转换为 1 再应用改变;变量类型从布尔值变成数值。
- 对于浮点值,加 1 或减 1。
- 如果是对象,则调用其
valueOf()
方法取得可以操作的值,对得到的值应用上述规则;如果是NaN
,则调用toString()
并再次应用其他规则。变量类型从对象变成数值
下面的例子演示了这些规则:
let s1 = "2";
let s2 = "z";
let b = false;
let f = 1.1;
let o = {
valueOf() {
return -1;
}
};
s1++; // 值变成数值 3
s2++; // 值变成 NaN
b++; // 值变成数值 1
f--; // 值变成 0.10000000000000009(因为浮点数不精确)
o--; // 值变成-2
复制代码
一元加与减
一元加和减操作符;一元加由一个加号(+)表示,放在变量前头,对数值没有任何影响:
let num = 25;
num = +num;
console.log(num); // 25
复制代码
如果将一元加应用到非数值,则会执行与使用 Number()转型函数一样的类型转换:布尔值 false和 true 转换为 0 和 1,字符串根据特殊规则进行解析,对象会调用它们的 valueOf()
和/或 toString()
方法以得到可以转换的值。
下面的例子演示了一元加在应用到不同数据类型时的行为:
let s1 = "01";
let s2 = "1.1";
let s3 = "z";
let b = false;
let f = 1.1;
let o = {
valueOf() {
return -1;
}
};
s1 = -s1; // 值变成数值 -1
s2 = -s2; // 值变成数值 -1.1
s3 = -s3; // 值变成 NaN
b = -b; // 值变成数值 0
f = -f; // 变成 -1.1
o = -o; // 值变成数值 1
复制代码
一元减由一个减号(-)表示,放在变量前头,主要用于把数值变成负值; 示例如下:
let num = 25;
num = -num;
console.log(num); // -25
复制代码
对数值使用一元减会将其变成相应的负值;在应用到非数值时,一元减会遵循与一元加同样的规则,先对它们进行转换,然后再取负值:
let s1 = "01";
let s2 = "1.1";
let s3 = "z";
let b = false;
let f = 1.1;
let o = {
valueOf() {
return -1;
}
};
s1 = +s1; // 值变成数值 1
s2 = +s2; // 值变成数值 1.1
s3 = +s3; // 值变成 NaN
b = +b; // 值变成数值 0
f = +f; // 不变,还是 1.1
o = +o; // 值变成数值-1
复制代码
一元加和减操作符主要用于基本的算术,但也可以像上面的例子那样,用于数据类型转换。
总结
一元运算符是 ECMAScript 中最简单的运算符,它只有一个参数,即要操作的对象或值
最主要的还是前缀与后缀的区别,前缀是求值前改值,后缀是求值后改值
简单过一下转换规则:
- 如果是有效的字符串,则转换数值再应用改变;
- 如果是无效的字符串,则将变量的值设置为NaN
- 如果布尔值的值为
true
,则转化为1;若为false
,则转换为 0 - 对于浮点值,加1 或 减1
- 如果是对象,调用
valueOf()
方法取到可以操作的值;若为NaN
,则调用toString()
;