JavaScript(十二)操作符:一元、加性、乘性、指数

1,131 阅读6分钟

ECMA-262 描述了一组可用于操作数据值的操作符(operate)。

一元操作符

只操作一个值的操作符叫一元操作符(unary operator)。一元操作符是 ECMAScript 中最简单的操作符。

递增/递减操作符

递增和递减操作符是一种一元操作符,它直接照搬自 C 语言。根据前缀和后缀两个版本,它一共有四种情况:

++age; // 前缀递增版
--age; // 前缀递减版
age++; // 后缀递增版
age--; // 后缀递减版

使用前缀版时,变量的值会在语句被求值前就改变。在计算机科学中,这通常被称为具有副作用:

newAge = ++age + 1;

// 等价于
age = age + 1;
newAge = age + 1;

而后缀版则相反:

newAge = age++ + 1;

// 等价于
newAge = age + 1;
age = age + 1;

这 4 个操作符可以作用于任何值。遵循如下规则:

  1. 字符串,如果是有效的数值形式,则转换为数值再应用改变。变量类型从字符串变成数值。
  2. 字符串,如果不是有效的数值形式,则将变量的值设置为 NaN 。变量类型从字符串变成数值。
  3. 布尔值,如果是 false,则转换为 0 再应用改变。变量类型从布尔值变成数值。
  4. 布尔值,如果是 true,则转换为 1 再应用改变。变量类型从布尔值变成数值。
  5. 浮点值,加 1 或减 1。
  6. 对象,则调用其 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

一元加/减

如果将一元加应用到非数值,则会执行与使用 Number()转型函数一样的类型转换,之后再赋值正或负。

布尔值 false 和 true 转换为 0 和 1,再赋正负。

字符串如果可以转换成数值就附上正负,如果不能就得到NaN。

对象会调用它们的 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 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 result = 1 + 2;

如果两个操作数都是数值:

  1. 如果有任一操作数是 NaN,则返回 NaN;

  2. 如果是 Infinity 加 Infinity,则返回 Infinity;

  3. 如果是-Infinity 加-Infinity,则返回-Infinity;

  4. 如果是 Infinity 加-Infinity,则返回 NaN;

  5. 如果是+0 加+0,则返回+0;

  6. 如果是-0 加+0,则返回+0;

  7. 如果是-0 加-0,则返回-0。

如果有一个操作数是字符串:

  1. 另一个也是字符串,则按先后顺序拼接两个字符串;

  2. 另一个操作数是对象、数值或布尔值,则调用它们的 toString()方法以获取字符串,然后拼接。对于 undefined 和 null,则调用 String()函数,分别获取"undefined"和"null"。

比如:

let result2 = 5 + "5"; // 一个数值和一个字符串
console.log(result2); // "55"

减法操作符

一般用于数值相减。

减法操作符的特殊情况和加法有些不同:

  1. 如果有任一操作数是 NaN,则返回 NaN。
  2. 如果是 Infinity 减 Infinity,则返回 NaN。
  3. 如果是-Infinity 减-Infinity,则返回 NaN。
  4. 如果是 Infinity 减-Infinity,则返回 Infinity。
  5. 如果是-Infinity 减 Infinity,则返回-Infinity。
  6. 如果是+0 减+0,则返回+0。
  7. 如果是+0 减-0,则返回-0。
  8. 如果是-0 减-0,则返回+0。
  9. 如果有任一操作数是字符串、布尔值、null 或 undefined,则先在后台使用 Number()将其转换为数值,然后再根据前面的规则执行数学运算。如果转换结果是 NaN,则减法计算的结果是 NaN。
  10. 如果有任一操作数是对象,则调用其 valueOf()方法取得表示它的数值。如果该值是 NaN,则减法计算的结果是 NaN。如果对象没有 valueOf()方法,则调用其 toString()方法,然后再将得到的字符串转换为数值。

可以看一下下面的例子:

let result1 = 5 - true; // true 被转换为1,所以结果是4
let result2 = NaN - 1; // NaN
let result3 = 5 - 3; // 2
let result4 = 5 - ""; // ""被转换为0,所以结果是5
let result5 = 5 - "2"; // "2"被转换为2,所以结果是3
let result6 = 5 - null; // null 被转换为0,所以结果是5

乘性操作符

ECMAScript 定义了 3 个乘性操作符:乘法、除法和取模。如果乘性操作符有不是数值的操作数,则该操作数会被 Number()转型函数转换为数值。

乘法操作符

乘法操作符由一个星号(*)表示,可以用于计算两个数值的乘积:

let result = 34 * 56;

当遇到特殊值时:

  1. 如果有任一操作数是 NaN,则返回 NaN。
  2. 如果是 Infinity 乘以 0,则返回 NaN。
  3. 如果是 Infinity 乘以非 0 的有限数值,则根据第二个操作数的符号返回 Infinity 或-Infinity。
  4. 如果是 Infinity 乘以 Infinity,则返回 Infinity。
  5. 如果有不是数值的操作数,则先在后台用 Number()将其转换为数值,然后再应用上述规则。

除法操作符

除法操作符由一个斜杠(/)表示,用于计算第一个操作数除以第二个操作数的商:

let result = 66 / 11;

当遇到特殊值时:

  1. 如果有任一操作数是 NaN,则返回 NaN。
  2. 如果是 Infinity 除以 Infinity,则返回 NaN。
  3. 如果是 0 除以 0,则返回 NaN。
  4. 如果是非 0 的有限值除以 0,则根据第一个操作数的符号返回 Infinity 或-Infinity。
  5. 如果是 Infinity 除以任何数值,则根据第二个操作数的符号返回 Infinity 或-Infinity。
  6. 如果有不是数值的操作数,则先在后台用 Number()函数将其转换为数值,然后再应用上述规则。

取模操作符

取模操作符,即取余数。由一个百分比符号(%)表示:

let result = 26 % 5; // 等于1

当遇到特殊值时:

  1. 如果被除数是无限值,除数是有限值,则返回 NaN。
  2. 如果被除数是有限值,除数是 0,则返回 NaN。
  3. 如果是 Infinity 除以 Infinity,则返回 NaN。
  4. 如果被除数是有限值,除数是无限值,则返回被除数。
  5. 如果被除数是 0,除数不是 0,则返回 0。
  6. 如果有不是数值的操作数,则先在后台用 Number()函数将其转换为数值,然后再应用上述规则。

指数操作符

指数操作符**和 Math.pow()一样:

console.log(Math.pow(3, 2); // 9
console.log(3 ** 2); // 9
console.log(Math.pow(16, 0.5); // 4
console.log(16** 0.5); // 4

指数操作符还可以用指数赋值操作符**=,该操作符执行指数运算和结果的赋值操作:

let squared = 3;
squared **= 2; // 9