一个或运算 || 的链,将返回第一个真值,如果不存在真值,就返回该链的最后一个值。
例如:
alert( 1 || 0 ); // 1(1 是真值)
alert( null || 1 ); // 1(1 是第一个真值)
alert( null || 0 || 1 ); // 1(第一个真值)
alert( undefined || null || 0 ); // 0(都是假值,返回最后一个值)
与运算返回第一个假值,如果没有假值就返回最后一个值。
上面的规则和或运算很像。区别就是与运算返回第一个假值,而或运算返回第一个真值。
// 如果第一个操作数是真值,
// 与运算返回第二个操作数:
alert( 1 && 0 ); // 0
alert( 1 && 5 ); // 5
// 如果第一个操作数是假值,
// 与运算将直接返回它。第二个操作数会被忽略
alert( null && 5 ); // null
alert( 0 && "no matter what" ); // 0
与运算 && 在或运算 || 之前进行
与运算 && 的优先级比或运算 || 要高。
所以代码 a && b || c && d 跟 && 表达式加了括号完全一样:(a && b) || (c && d)。
两个非运算 !! 有时候用来将某个值转化为布尔类型:
第一个非运算将该值转化为布尔类型并取反,第二个非运算再次取反。最后我们就得到了一个任意值到布尔值的转化。
alert( null || 2 && 3 || 4 );
运算 && 的优先级比 || 高,所以它第一个被执行。
结果是 2 && 3 = 3,所以表达式变成了:
null || 3 || 4
现在的结果就是第一个真值:3。
空值合并运算符 '??'
如果第一个参数不是 null/undefined,则 ?? 返回第一个参数。否则,返回第二个参数。
通常 ?? 的使用场景是,为可能是未定义的变量提供一个默认值。
例如,在这里,如果 user 是未定义的,我们则显示 Anonymous:
let user;
alert(user ?? "Anonymous"); // Anonymous
?? 运算符的优先级相当低:在 MDN table 中为 5。因此,?? 在 = 和 ? 之前计算,但在大多数其他运算符(例如,+ 和 *)之后计算。