先记住这个答案
和很多语言不同,JavaScript 的 || 和 && 不是返回 true 或 false,而是返回两个操作数中的某一个原值。引擎先对左侧做真假判断:|| 遇到真值就返回它,否则返回右侧;&& 遇到假值就返回它,否则返回右侧。被跳过的一侧完全不会求值,这就是短路求值。
- 返回的是原操作数,不是布尔值
||返回第一个真值,&&返回第一个假值- 短路求值:被跳过的表达式不会执行
0和空字符串是假值,用||给默认值会误覆盖
返回的是原值,不是布尔
面试时很多人会说"|| 左真返回 true",这是不对的。它返回的是那个操作数本身,类型也保持不变。这个特性让 || 和 && 除了做逻辑判断之外,还可以用来选值和做条件执行。
console.log('hello' || 'world');
console.log(0 || 'fallback');
console.log('hello' && 42);
console.log(null && 42);
console.log(0 || false || 'last');
console.log(1 && 2 && 3);查看输出与解释
hello
fallback
42
null
last
3第一行 'hello' 是真值,|| 直接返回它,'world' 根本没被求值。第四行 null 是假值,&& 直接返回 null,右侧的 42 被跳过。链式 || 返回第一个真值,链式 && 返回第一个假值,如果找不到就返回最后一个值。
这也是 cache || createCache() 这种写法能成立的原因:如果 cache 有值(真值),直接用它,createCache() 根本不会被调用;如果 cache 是 null 或 undefined(假值),才会调用右侧函数创建新的。
短路求值的副作用问题
短路不只是跳过求值那么简单。如果被跳过的表达式里有函数调用、赋值、自增等副作用,这些副作用就不会发生。利用得好可以做条件执行,用不好会引入隐蔽的 bug。
isReady && render() 只在 isReady 为真时才调用 render(),效果和 if (isReady) render() 一样。但如果 render() 有错误处理需求,或者后面还有别的逻辑,短路写法会让代码变得难以维护。多步骤逻辑还是用 if 更清晰。
|| 给默认值的坑JavaScriptconsole.log(0 || 100);
console.log('' || 'anonymous');
console.log(false || true);查看输出与解释
100
anonymous
true0、空字符串、false 都是假值,|| 会把它们当成"没有值"而覆盖掉。但在很多场景下这些都是合法的业务数据:分数为 0、用户没填昵称用空字符串、开关关闭用 false。如果用 score || 100 做默认值,零分的学生会被显示成 100 分。这个问题用 ?? 可以解决,?? 只在左侧是 null 或 undefined 时才回退。
容易答错的地方
- 以为返回值一定是布尔
'hello' || 0返回的是字符串"hello",不是true。如果把逻辑运算的结果传给需要布尔值的 API,可能会出问题。需要布尔值时应该用Boolean()或!!显式转换。- 用
||给所有字段设默认值 0、false、空字符串都会被覆盖。只想兜底null和undefined时,应该用??而不是||。
面试官还会怎么问?
a && b && c 返回什么?
从左到右求值,遇到第一个假值就返回它。如果全部为真,返回最后一个值 c。比如 1 && 'hello' && [] 返回 [](空数组是真值)。
短路能阻止函数参数的求值吗?
能。false && fn(expensiveCalc()) 里 fn 不会被调用,expensiveCalc() 也不会被调用。整个右侧表达式被完整跳过。但不要把必须执行的副作用放在可能被跳过的位置。
|| 和 ?? 什么时候该用哪个?
如果左侧可能是 0、false、空字符串这些合法值,用 ??。如果你确实想把所有假值都替换成默认值,用 ||。实际项目中大部分场景应该用 ??,因为"没有值"通常只是 null 和 undefined。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。