JavaScript for impatient programmers (ES2022 edition)
请支持本书:购买捐赠
(广告,请不要屏蔽。)

15 布尔值



基本类型*布尔值*包含两个值 - falsetrue

> typeof false
'boolean'
> typeof true
'boolean'

15.1 转换为布尔值

  “转换为 [类型]” 的含义

“转换为 [类型]” 是 “将任意值转换为 [类型] 类型的值” 的简称。

您可以通过以下三种方式将任意值 x 转换为布尔值。

表 4 描述了如何将各种值转换为布尔值。

表 4:将值转换为布尔值。
x Boolean(x)
undefined false
null false
boolean x (无变化)
number 0 false, NaN false
其他数字 true
bigint 0 false
其他数字 true
string '' false
其他字符串 true
symbol true
object 始终为 true

15.2 假值和真值

在检查 if 语句、while 循环或 do-while 循环的条件时,JavaScript 的工作方式可能与您预期的不同。以以下条件为例

if (value) {}

在许多编程语言中,此条件等效于

if (value === true) {}

但是,在 JavaScript 中,它等效于

if (Boolean(value) === true) {}

也就是说,JavaScript 会检查 value 转换为布尔值时是否为 true。这种检查非常普遍,因此引入了以下名称

每个值要么是真值,要么是假值。查阅表 4,我们可以列出所有假值

所有其他值(包括所有对象)都是真值

> Boolean('abc')
true
> Boolean([])
true
> Boolean({})
true

15.2.1 检查真值或假值

if (x) {
  // x is truthy
}

if (!x) {
  // x is falsy
}

if (x) {
  // x is truthy
} else {
  // x is falsy
}

const result = x ? 'truthy' : 'falsy';

最后一行中使用的条件运算符将在本章稍后解释

  练习:真值

exercises/booleans/truthiness_exrc.mjs

15.3 基于真值的存性检查

在 JavaScript 中,如果您读取不存在的内容(例如,缺少的参数或缺少的属性),您通常会得到 undefined 作为结果。在这些情况下,存性检查相当于将值与 undefined 进行比较。例如,以下代码检查对象 obj 是否具有属性 .prop

if (obj.prop !== undefined) {
  // obj has property .prop
}

由于 undefined 是假值,我们可以将此检查缩短为

if (obj.prop) {
  // obj has property .prop
}

15.3.1 陷阱:基于真值的存性检查不精确

基于真值的存性检查有一个陷阱:它们不是很精确。考虑前面的例子

if (obj.prop) {
  // obj has property .prop
}

如果满足以下条件,则跳过 if 语句的主体

但是,如果满足以下条件,也会跳过它

在实践中,这很少会导致问题,但您必须意识到这个陷阱。

15.3.2 用例:是否提供了参数?

真值检查通常用于确定函数的调用者是否提供了参数

function func(x) {
  if (!x) {
    throw new Error('Missing parameter x');
  }
  // ···
}

从好的方面来说,这种模式是既定的,而且很短。它会针对 undefinednull 正确地抛出错误。

从不好的方面来说,存在前面提到的陷阱:该代码还会针对所有其他假值抛出错误。

另一种方法是检查 undefined

if (x === undefined) {
  throw new Error('Missing parameter x');
}

15.3.3 用例:属性是否存在?

真值检查也经常用于确定属性是否存在

function readFile(fileDesc) {
  if (!fileDesc.path) {
    throw new Error('Missing property: .path');
  }
  // ···
}
readFile({ path: 'foo.txt' }); // no error

这种模式也是既定的,并且具有通常的注意事项:它不仅在属性缺失时抛出,而且在属性存在且具有任何假值时也会抛出。

如果您真的想检查属性是否存在,则必须使用in 运算符

if (! ('path' in fileDesc)) {
  throw new Error('Missing property: .path');
}

15.4 条件运算符 (? :)

条件运算符是 if 语句的表达式版本。其语法为

«condition» ? «thenExpression» : «elseExpression»

它的计算方式如下

条件运算符也称为*三元运算符*,因为它有三个操作数。

示例

> true ? 'yes' : 'no'
'yes'
> false ? 'yes' : 'no'
'no'
> '' ? 'yes' : 'no'
'no'

以下代码演示了无论通过条件选择“then”和“else”中的哪一个分支,都只计算该分支。另一个分支不计算。

const x = (true ? console.log('then') : console.log('else'));

// Output:
// 'then'

15.5 二元逻辑运算符:与 (x && y),或 (x || y)

二元逻辑运算符 &&|| 是*值保留*和*短路求值*的。

15.5.1 值保留

*值保留*意味着操作数被解释为布尔值,但返回时保持不变

> 12 || 'hello'
12
> 0 || 'hello'
'hello'

15.5.2 短路求值

*短路求值*意味着如果第一个操作数已经确定了结果,则不计算第二个操作数。唯一另一个延迟计算其操作数的运算符是条件运算符。通常,在执行操作之前会计算所有操作数。

例如,如果第一个操作数为假值,则逻辑与 (&&) 不会计算其第二个操作数

const x = false && console.log('hello');
// No output

如果第一个操作数为真值,则执行 console.log()

const x = true && console.log('hello');

// Output:
// 'hello'

15.5.3 逻辑与 (x && y)

表达式 a && b(“ab”)的计算方式如下

  1. 计算 a
  2. 结果是假值吗?返回它。
  3. 否则,计算 b 并返回结果。

换句话说,以下两个表达式大致等效

a && b
!a ? a : b

示例

> false && true
false
> false && 'abc'
false

> true && false
false
> true && 'abc'
'abc'

> '' && 'abc'
''

15.5.4 逻辑或 (||)

表达式 a || b(“ab”)的计算方式如下

  1. 计算 a
  2. 结果是真值吗?返回它。
  3. 否则,计算 b 并返回结果。

换句话说,以下两个表达式大致等效

a || b
a ? a : b

示例

> true || false
true
> true || 'abc'
true

> false || true
true
> false || 'abc'
'abc'

> 'abc' || 'def'
'abc'
15.5.4.1 逻辑或 (||) 的传统用例:提供默认值

ECMAScript 2020 引入了空值合并运算符 (??) 来提供默认值。在此之前,逻辑或用于此目的

const valueToUse = receivedValue || defaultValue;

有关 ?? 以及在这种情况下 || 的缺点的更多信息,请参阅§14.4 “空值合并运算符 (??) 用于默认值 [ES2020]”

  传统练习:通过或运算符 (||) 提供默认值

exercises/booleans/default_via_or_exrc.mjs

15.6 逻辑非 (!)

表达式 !x(“非 x”)的计算方式如下

  1. 计算 x
  2. 它是真值吗?返回 false
  3. 否则,返回 true

示例

> !false
true
> !true
false

> !0
true
> !123
false

> !''
true
> !'abc'
false

  测验

请参阅测验应用程序