
本文详解 JavaScript 中 && 和 || 的求值机制,指出直接在 includes() 中嵌套逻辑表达式的常见误区,并提供清晰、可复用的解决方案,帮助开发者准确判断数组是否同时包含多个目标值(如井字棋获胜组合)。
本文详解 javascript 中 `&&` 和 `||` 的求值机制,指出直接在 `includes()` 中嵌套逻辑表达式的常见误区,并提供清晰、可复用的解决方案,帮助开发者准确判断数组是否同时包含多个目标值(如井字棋获胜组合)。
在实现井字棋(Tic-Tac-Toe)胜负判定时,一个典型需求是:验证某位玩家(如 "X")是否已占据某条获胜线上的全部三个位置(例如位置 1、4、7 构成竖直左列)。许多初学者会尝试如下写法:
// ❌ 错误示例:逻辑运算符被错误地用于数值组合
if (moves_counter_x.includes(1 && 4 && 7)) { ... }这段代码看似“检查是否包含 1、4 和 7”,但实际执行逻辑完全不同。JavaScript 中,1 && 4 && 7 是一个纯布尔求值表达式:它从左到右依次计算,返回最后一个被强制转换为真值的 operand(即 7),因为 1 和 4 均为 truthy 值。因此,该语句等价于:
moves_counter_x.includes(7) // 仅检查是否含 7!
同理,1 && 2 && 3 || 4 && 5 && 6 会被求值为 3 || 6 → 3(因 3 为 truthy,短路返回),最终仍只调用 includes(3) —— 这就是为何即使 moves_counter_x = [1, 5, 6](不构成任何胜局),函数也总误判为 “X 获胜”。
✅ 正确做法是:对每个目标数字独立调用 includes(),再用 && 连接结果,确保全部存在;多组获胜条件之间用 || 连接。例如:
function result_check() {
const x = moves_counter_x;
if (
(x.includes(1) && x.includes(4) && x.includes(7)) || // 左列
(x.includes(2) && x.includes(5) && x.includes(8)) || // 中列
(x.includes(3) && x.includes(6) && x.includes(9)) || // 右列
(x.includes(1) && x.includes(2) && x.includes(3)) || // 上行
(x.includes(4) && x.includes(5) && x.includes(6)) || // 中行
(x.includes(7) && x.includes(8) && x.includes(9)) // 下行
) {
console.log("X won");
}
}? 关键理解:
- && 和 || 操作的是表达式的返回值(这里是布尔值),而非“参数列表”;
- includes() 接收单个值作为参数,无法原生支持“多值同时存在”的语义。
? 进阶优化(推荐用于中大型项目):
可将所有获胜组合预定义为二维数组,结合 some() + every() 提升可读性与可维护性:
const winPatterns = [
[1, 4, 7], [2, 5, 8], [3, 6, 9], // 列
[1, 2, 3], [4, 5, 6], [7, 8, 9], // 行
[1, 5, 9], [3, 5, 7] // 对角线
];
function result_check() {
const x = moves_counter_x;
if (winPatterns.some(pattern =>
pattern.every(pos => x.includes(pos))
)) {
console.log("X won");
}
}⚠️ 注意事项:
- 确保 moves_counter_x 是普通数组(非 Set);若使用 Set,应改用 has() 方法;
- 数字 ID 应与 DOM 元素 ID 或游戏坐标严格一致,避免索引偏移(如 0-based vs 1-based);
- 实际项目中建议将 "X" 和 "O" 的判定逻辑封装为独立函数,避免重复代码。
掌握逻辑运算符的作用对象与 includes() 的参数语义,是写出健壮条件判断的基础——勿让求值顺序成为隐藏 Bug 的温床。

















