应将低成本、高拦截率的前置条件置于逻辑表达式左侧,高成本安全校验置于右侧,利用短路机制避免不必要开销;需显式进行空值与边界检查,禁用隐式falsy判断;含副作用操作不可置于&&右侧。

把性能开销最大的安全防御校验放到逻辑表达式最右侧,而把轻量、高拦截率的前置条件放在左侧——短路不是为了“省一点”,而是确保高成本操作只在真正必要时才执行。
优先安排低成本、高失败率的拦截条件
数据库查询、远程鉴权、配置加载等操作一旦触发就不可逆。必须让它们出现在 && 的最右边,左边全是“秒判”条件:
- 参数非空且类型正确:比如
id != null && typeof id === 'number' - 基础范围校验:如
id > 0 && id < 1000000,防穿透和日志污染 - 状态标记检查:如
user?.status === 'active',不查库就能否决
用具名布尔变量封装语义,避免长链嵌套
直接写 req.user && req.user.role && req.user.role === 'admin' && checkPermission(req.user.id, 'delete') && db.deleteItem(id) 看似紧凑,实则难调试、难复用、易出错。应拆解为:
const hasValidUser = req.user && typeof req.user.id === 'number';const isAdmin = hasValidUser && req.user.role === 'admin';const hasDeletePerm = isAdmin && checkPermission(req.user.id, 'delete');- 再组合:
hasValidUser && isAdmin && hasDeletePerm && db.deleteItem(id)
每一步含义清晰,单元测试可覆盖,后续扩展权限规则也只需改对应变量。
警惕副作用被跳过,关键动作必须显式控制
短路会跳过右侧表达式,所以含副作用的操作(如审计日志、失败计数、告警上报)绝不能塞进 && 右侧:
- ❌ 错误:
isValid && logAudit('delete', user.id) && db.deleteItem(id)—— 日志可能根本没记 - ✅ 正确:
if (isValid) { logAudit('delete', user.id); db.deleteItem(id); }
同理,缓存未命中后查库可用 ||,但若需同时记录“缓存未命中”指标,就得单独写一行:const cached = cache.get(key); if (!cached) recordCacheMiss(); return cached || db.fetch(key);
防御性空值与边界检查要显式、不依赖隐式 falsy
JavaScript 中 []、{}、0、'0' 都是 truthy/falsy,但业务语义完全不同:
- 数组为空?别用
items && items.length,而用Array.isArray(items) && items.length > 0 - 字符串非空?别用
str,而用typeof str === 'string' && str.trim() !== '' - 对象有关键字段?别用
user && user.email,而用user && typeof user === 'object' && 'email' in user && user.email
这些判断本身轻量,却能精准拦截大量非法输入,让后面的重操作根本不启动。


















