引子
本文讲述了 ECMA-262 中可用于操作数据值的操作符之布尔操作符;
ECMAScript 中的操作符是独特的,因为它们可用于各种值,包括字符串、数值、布尔值,甚至还有对象;在应用给对象时,操作符通常会调用 valueOf() 或 toString() 方法来取得可以计算的值。
布尔操作符
布尔操作符一共有 3 个:逻辑非(NOT) 、逻辑与(AND) 与和逻辑或(OR) ,它跟相等操作符几乎同样重要
逻辑非
逻辑非操作符由一个叹号(!)表示,可应用给 ECMAScript 中的任何值;这个操作符始终返回布尔值,无论应用到的是什么数据类型。
逻辑非操作符首先将操作数转换为布尔值,然后再对其取反;
逻辑非操作符规则:
- 如果操作数是对象,则返回
false - 如果操作数是空字符串,则返回
false - 如果操作数是非空字符串,则返回
false - 如果操作数是数值 0,则返回
true - 如果操作数是 null ,则返回
true - 如果操作数是 NaN,则返回
true - 如果操作数是 undefined,则返回
true
代码演示
console.log(!false); // true
console.log(!"blue"); // false
console.log(!0); // true
console.log(!NaN); // true
console.log(!""); // true
console.log(!12345); // false
取反操作
同时使用两个叹号(!!)也可以把任意值转换为布尔值,相当于调用了转型函数 Boolean();
无论操作数是什么类型,第一个叹号总会返回布尔值,第二个叹号对该布尔值取反,从而给出变量真正对应的布尔值,结果与对同一个值使用 Boolean() 函数是一样的。
如下所示:
console.log(!!"blue"); // true
console.log(!!0); // false
console.log(!!NaN); // false
console.log(!!""); // false
console.log(!!12345); // true
逻辑与
逻辑与操作符由两个和号(&&)表示,应用到两个值;
简单口诀:一个为false则都为false
它可用于任何类型的操作数,不限于布尔值
逻辑与操作符规则
如果有操作数不是布尔值,则逻辑与并不一定会返回布尔值,而是遵循如下规则:
- 如果第一个操作数是对象,则返回第二个操作数
- 如果第二个操作数是对象,则只有第一个操作数求值为 true 才会返回对象
- 如果两个操作数是对象,则返回第二个操作数
- 如果有一个操作数是 null ,则返回
null - 如果有一个操作数是 NaN,则返回
NaN - 如果有一个操作数是 undefined,则返回
undefined
短路特性
可以说逻辑与操作符是一种短路操作符,就是如果第一个操作数决定了结果,那么永远不会对第二个操作数求值;对逻辑与操作符来说,如果第一个操作数是 false,那么无论第二个操作数是什么值,结果也不可能等于 true。
来看下面这两个例子:
let found = true;
let result = (found && test); // 报错
console.log(result); // 不会执行
/* 相反如果第一个为false则不会报错 */
let found = false;
let result = (found && test); // 不会出错
console.log(result); // 会执行
第一例子虽然 found为true 会执行检索下一个值 但是因为 test 没定义,所以报错,result也不会执行;第二个例子因为 found为false 所以不用再执行test了,直接把false 赋给result。
注意: 在使用逻辑与操作符时,一定别忘了它的这个短路的特性
逻辑或
逻辑或操作符由两个管道符(||)表示,同样应用到两个值;
简单口诀:全都为 true 才返回 ture
与逻辑与类似,如果有一个操作数不是布尔值,那么逻辑或操作符也不一定返回布尔值。
逻辑或操作符规则
- 如果第一个操作数是对象,则返回第一个操作数
- 如果第一个操作数求值为false,则返回第二个操作数
- 如果两个操作数都是对象,则返回第一个操作数
- 如果两个操作数都是 null ,则返回
null - 如果两个操作数都是NaN,则返回
NaN - 如果两个操作数都是 undefined ,则返回
undefined
短路特性
同样与逻辑与类似,逻辑或操作符也具有短路的特性;只不过对逻辑或而言,第一个操作数求值为true,第二个操作数就不会再被求值了;
来看下面这几个例子:
let found = true;
let result = (found || test); // 不会出错
console.log(result); // 会执行
/* 与逻辑或相反 o( ̄▽ ̄)d */
let found = false;
let result = (found || test); // 这里会出错
console.log(result); // 不会执行这一行
第一例子中 found为true 会直接将值赋给result ,也不用再执行 test了;第二个例子虽然 found为false 但是逻辑与还会再检测下一个,发现 test 未定义,直接报错也不会执行 result。
小知识
利用这个行为,可以避免给变量赋值 null 或 undefined;如下所示:
let myObject = preferredObject || backupObject;
在这个例子中,变量 myObject 会被赋予两个值中的一个;其中,preferredObject 变量包含首选的值,backupObject 变量包含备用的值;如果 preferredObject 不是 null,则它的值就会赋给myObject;如果 preferredObject 是 null,则 backupObject 的值就会赋给 myObject。
PS: 这种模式在 ECMAScript 代码中经常用于变量赋值
总结
布尔操作符几乎在所有编程语言中都很重要,主要场景用于比较与校验
- 逻辑非: 也称为取反操作符,
!用于取反;!!用于将值返回成布尔值再取反; - 逻辑与:
&&如果一个为 false ,则都为 false - 逻辑或:
||如果都为 true ,才返回 true - 使用逻辑或对变量赋值可以校验是否为
null或undefined