bug记录:由运算符优先级导致的bug

112 阅读1分钟

记录:由运算符优先级导致的bug

错误代码以及问题现象

组件日期格式始终显示为 YYYY-MM-DD HH:mm:ss,即使已显式传入 format 参数

<DatePicker 
  format={format ?? showTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD'}
/>

原因分析

运算符优先级混淆

JavaScript 运算符优先级表(部分):

运算符优先级结合性
?? (空值合并)5从左到右
?: (三元运算)4从右到左

实际执行逻辑:

// 等效于
(format ?? showTime) ? '...HH:mm:ss' : '...YYYY-MM-DD'

format 存在值时:

  1. ?? 先执行返回非空值
  2. 将非空值转换为布尔值进行三元运算
  3. 任何真值都会触发选择时间格式

解决方案

正确写法

// ✅ 正确使用括号明确优先级
<DatePicker
  format={format ?? (showTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD')}
/>

执行逻辑分解

  1. 优先处理三元表达式:
    const defaultFormat = showTime ? '...HH:mm:ss' : '...YYYY-MM-DD';
    
  2. 执行空值合并运算:
    finalFormat = format ?? defaultFormat;
    

验证示例

测试用例原代码结果修正后结果
format="YYYY/MM/DD"HH:mm:ss 格式YYYY/MM/DD
format=null, showTime=trueHH:mm:ss 格式HH:mm:ss 格式
format=undefined, showTime=falseHH:mm:ss 格式YYYY-MM-DD

最佳实践

  1. 括号优先原则:混合使用逻辑运算符时显式使用括号
  2. 分步处理:对复杂逻辑进行分解
    const getDefaultFormat = () => 
      showTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD';
    
    <DatePicker format={format ?? getDefaultFormat()} />
    
  3. 类型守卫:严格判断空值
    const finalFormat = typeof format === 'string' ? format : defaultFormat;
    

关键点:当 ???: 混合使用时,永远显式使用括号明确优先级关系。