现代 JavaScript 从头再来(三):运算符

59 阅读4分钟

运算符

运算符应用的对象叫做运算元,运算符对应的有几个运算元就是几元运算符:

let a = 1;
a = -a; "-" 是一元运算符,在这里表示负号运算符
​
let x = 3;
let y = 2;
let result = y - x; "-" 是二元运算符,在这里表示减法运算符

数学运算符

  • 加法 +
  • 减法 -
  • 乘法 *
  • 除法 /
  • 取余 %
  • 求幂 **
// 取余
console.log(5 % 2); // 1,5 除以 2 的余数// 求幂
console.log(2 ** 3); // 8,2 的 3 次方
console.log(8 ** (1/3)); // 2,8 的立方根

二元运算符 +

+ 也可以用于连接字符串:

console.log('hello' + 'world'); // helloworld// 只有任意一个运算元是字符串,那么另一个运算元也会被转化为字符串
console.log(1 + '2'); // '12'// 运算符按顺序工作
console.log(1 + 1 + '2'); // '22'
console.log('1' + 1 + 2); // '112'

二元 + 是唯一一个以这种方式支持字符串的运算符。其他算术运算符只对数字起作用,并且总是将运算元转换为数字

console.log(3 - '2'); // 1,将 '2' 转换为数字
console.log('6' / '3'); // 2,将两个运算元都转换为数字

一元运算符 +

常用于字符串转数字,效果等同于 Number(value) ,但是更为简洁:

let a = '1';
let b = '2';
​
console.log(+a + +b); // 3
​
// 等同于
// console.log(Number(a) + Number(b)); // 3

运算符是有优先级的,一元运算符的优先级高于二元运算符

赋值运算符 =

js 中所有的运算符都会返回一个值,其中也包括 =

let a = 1;
let b = 2;
let c = 3 - (a = b + 1);
​
console.log(a); // 3
console.log(c); // 0

修改并赋值运算符

所有算术和位运算符都支持这种运算符:

let n = 2;
n += 1;
n *= 2;
n /= 2;
n -= 1;
console.log(n); // 2

这类运算符的优先级与普通赋值运算符的优先级相同

自增/自减

++-- ,可以前置也可以后置,前置形式返回一个新的值,而后置会返回原来的值(做加法/减法之前的值)

自增/自减只能应用于变量,将其应用于数值(比如 1++)则会报错

  • 如果自增/自减的值不会被使用,则两者没有区别

    let count = 0;
    count++;
    ++count;
    console.log(count); // 2
    
  • 如果想使用自增/自减后的值,那么需要使用前置形式:

    let count = 0;
    console.log(++count); // 1
    
  • 如果想使用自增/自减前的值,那么需要使用后置形式:

    let count = 0;
    console.log(count++); // 0
    

++/-- 运算符的优先级比绝大部分的算数运算符要高:

let count = 0;
console.log(2 * ++count); // 2

比较运算符

  • >>=<<=
  • 非严格相等 == 和严格相等 ===
  • 非严格不等!= 和严格不等 !==

比较运算符始终返回布尔值

和其他类型的值一样,比较的结果可以被赋值给任意变量:

let result = 2 > 1;
console.log(result); // true

字符串比较

会按照 Unicode 编码顺序逐字符地比较大小:

console.log('Z' > 'A'); // true
console.log('a' > 'A'); // true
console.log('Black' > 'Blue'); // true

不同类型间的比较

js 会首先将其转化为 number 类型再进行比较:

console.log('2' > 1); // true,字符串 '2' 会被转化为数字 2
console.log('01' == 1); // true,字符串 '01' 会被转化为数字 1

对 null 和 undefined 的比较

nullundefined 在相等性检查 == 中不会进行任何的类型转换,它们有自己独立的比较规则

在非严格相等 == 下,nullundefined 相等且各自不等于任何其他的值:

console.log(null == undefined); // true
console.log(null === undefined); // falseconsole.log(null > 0); // false
console.log(null == 0); // false
console.log(null >= 0); // true// undefined 转换为 number 类型是 NaN
console.log(undefined > 0); // false
console.log(undefined < 0); // false
console.log(undefined == 0); // false

NaN 是一个特殊的数值型值,它与任何值进行比较都会返回 false

逻辑运算符

js 中有四个逻辑运算符:||(或),&&(与),!(非),??(空值合并运算符)

如果操作数不是布尔值,那么它将会被转化为布尔值来参与运算:

if (1 || 0) { // 相当于 true || false
    console.log(1);
}

|| 或运算返回第一个真值:

let result = '' || 1 || false;
console.log(result); // 1

&& 与运算返回第一个假值,如果没有假值就返回最后一个值:

let result = 1 && true && 'abc';
console.log(result); // 'abc'

&& 的优先级比 ||

两个非运算 !! 有时候用来将某个值转化为布尔类型:

console.log(!!null); // false
console.log(!!''); // false

空值合并运算符

??|| 类似常用于提供默认值,但 || 不能区分 false0、空字符串、和 null/undefined

let result = a ?? b
// 等同于
// let result = (a !== null && a !== undefined) ? a : b;

位运算符

位运算符把运算元当做 32 位整数,并在它们的二进制表现形式上操作

  • 按位与 ( & )
  • 按位或 ( | )
  • 按位异或 ( ^ )
  • 按位非 ( ~ )
  • 左移 ( << )
  • 右移 ( >> )
  • 无符号右移 ( >>> )

要用到的时候去 MDN 上查询

逗号运算符

用于处理多个表达式,每个表达式都会运行,但只有最后一个的结果会被返回:

// 需要使用 ()
let a = (1 + 2, 3 + 4);
console.log(a); // 7

逗号运算符的优先级非常低,比 = 还要低

最少见最不常使用的运算符之一,为什么要了解这种运算符,因为有很多人喜欢这样装杯吗

当然不是,这样的技巧有很多 js 框架中都有使用:

// 一行上有三个运算符
for (let a = 1, b = 3, c = a * b; a < 10; a++) {}