1 逻辑运算符

1.1 基本用法

  • ||(或)
1
if(a || b){}

a 或者 b 有一个为真,返回true

  • &&(与)
1
if (a && b) {}

a 和 b 都为真,才会返回true

  • !(非)

对 a 的值取反。

  • !!(强制类型转换)

转换类型为boolean,这样做的目的就是保证值只能在true/false中取。

1
2
3
const num = 3
typeof !! (num & 1) // boolean
// tips: 判断是否为奇数,与!!(num % 2)同理

1.2 短路用法

&&的运算中,代码从左往右执行,找假值,如果是真就继续执行下一个,找不到就执行最后一个

1
2
3
4
5
6
7
// 遇到假值,返回这个假值,后续不再执行
console.log( null && 1 ); // null
console.log( 1 && 0 && 2 );;// 0
// 都为真,返回最后一个值
console.log( 123 && '中国'); // '中国' 
// 计算表达式a的运算结果,如果为true,则执行表达式b,并返回b的结果
表达式a && 表达式b

||的运算中,代码从左往右执行,找真值,如果是假就继续执行下一个,找不到就执行最后一个

1
2
3
4
5
6
7
// 遇到真值,返回这个真值,后续不会执行
console.log( 123 || '中国'); // 123
console.log(0 || 1 || 2);//1
// 都为假,返回最后一个值
console.log( undefined || 0); // 0 
// 计算表达式a的运算结果,如果为false,则执行表达式b,并返回b的结果
表达式a || 表达式b

我们可以利用短路运算符的特性对逻辑判断(switch\if..else)进行简写:

1
2
3
4
5
6
7
8
9
if(a > 5){
  b = 1
}else if(a < 5){
  b = 2
}else {
  b = 0
}
//可以写成:
b = (a > 5 && 1) || (a < 5 && 2) || 0;

1.3 赋值用法

  • 或等于(||=)
1
a ||= b 等同于 a || (a = b); 
  • 且等于(&&=)
1
a &&= b 等同于 a && (a = b);

2 零合并操作符

  • 零合并操作符 ?? 是一个逻辑操作符,只会在左侧的操作数为 null 或者 undefined 时,返回右侧操作数,否则返回左侧操作数。
1
expr1 ?? expr2
  • 空值合并操作符一般用来为常量提供默认值,保证常量不为 null 或者 undefined,以前一般使用 || 来做这件事 variable = variable || 'bar'

  • 然而,由于 || 是一个布尔逻辑运算符,左侧的操作数会被强制转换成布尔值用于求值。任何假值(0''NaNnullundefined)都不会被返回。这导致如果你使用 0''NaN 、false作为有效值,就会出现不可预料的后果。

  • ?? 可以理解为是 || 的升级版。

可以在浏览器中执行下面的代码感受一下:

1
2
3
4
5
6
7
8
9
undefined || 'default' // 'default'
null || 'default'      // 'default'
false || 'default'     // 'default'
0 || 'default'         // 'default'

undefined ?? 'default' // 'default'
null ?? 'default'      // 'default'
false ?? 'default'     // 'false'
0 ?? 'default'         // 0

另外在赋值的时候,可以运用逻辑空分配符 ??=

1
2
3
4
5
let obj = { b: null, c: 10 }
// obj.b ? null : obj.b = 20
obj.b ??= 20 // 等效于 obj.b ?? (obj.b = 20)
obj.c ??= 20 // 等效于 obj.c ?? (obj.c = 20)
console.log(obj) // { b: 20, c: 10 }

3 可选链操作符

  • 可选链操作符 ?. 允许读取位于连接对象链深处的属性的值,而不必验证链中的每个引用是否有效。

  • ?. 操作符的功能类似于 . 链式操作符,不同之处在于,在引用为 null 或者 undefined 的情况下不会引起错误,该表达式短路返回值是 undefined

  • 当尝试访问可能不存在的对象属性时,可选链操作符将会使表达式更短、更简明。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
const obj = {
  a: 'foo',
  b: {
    c: 'bar'
  }
}
console.log(obj.b?.c) // 输出 bar
console.log(obj.d?.c) // 输出 undefined
console.log(obj.func()) // Uncaught TypeError: obj.func is not a function
console.log(obj.func?.()) // 不报错,输出 undefined
复制代码
  • 以前可能会通过 obj && obj.a && obj.a.b 来获取一个深度嵌套的子属性,现在可以直接简写obj?.a?.b 即可。

  • 可选链除了可以用在获取对象的属性,还可以用在数组的索引 arr?.[index],也可以用在函数的判断 func?.(args),当尝试调用一个可能不存在的方法时也可以使用可选链,在函数不存在时返回 undefined 而不是直接抛异常。

1
const result = someInterface.customFunc?.()

4 按位取反操作符

  • 按位非操作符由一个波浪线~表示,执行按位非的结果就是返回数值的反码
1
2
3
4
5
6
7
let num5 = 25;//25 等于 00000000000000000000000000011001

let num6 = ~num5;//转换为 11111111111111111111111111100110

alert(num6);//输出 "-26"

// 相当于 -1减去当前值 或 相当于是对数值求负后减1
  • 立即执行函数:本质上就是将函数声明变成一个表达式,因此可以解析完直接调用。
  • 函数前加上~,其作用是把函数声明转换为表达式,这样就可以直接运行。
1
2
3
~function sayHello(){
    console.log('hello');
}()

这种简写只能用于无返回值的函数,否则会对函数的返回值进行运算,这样可能会导致最终的结果与期望值不一致。

1
2
3
!function() {return 1}()//false
~function() {return 1}()//-2
-function() {return false}()//0
  • -1转换为假值(应用于字符串的indexOf方法)

    1
    2
    3
    4
    5
    
    var str='haha'
    if(~str.indexOf('b')){  // 这样更加简洁
    	...
    }
    // 数组的indexOf可能会返回0,因此不建议使用~符号
    
  • 将Boolean转成1和0

    1
    2
    3
    
    ~~true===1 
     ~~false===0
     // 其实还有更精简的写法 +false 和 +true
    
  • 去小数

    1
    2
    
    ~~ 1.5 === 1
    ~~ -1.5 === -1 // 注意这里和floor()就不同了如果用floor 得到的是-2