多路取值
a-calc 3.x 引入了多路取值(Fallback)功能,允许你在表达式中指定多个变量路径,按优先级依次尝试,返回第一个非空值。这在处理不确定数据源或需要默认值的场景中非常实用。
基本语法
使用管道符 | 分隔多个变量路径,需要用括号包裹:
(变量1 | 变量2 | 变量3 | ...)系统会从左到右依次尝试每个路径,返回第一个非空值。
基础用法
简单取值
javascript
import { calc } from 'a-calc'
// 第一个值为 null,自动取第二个
calc('(a | b) + 1', { a: null, b: 10 }) // '11'
// 第一个值为 undefined,自动取第二个
calc('(a | b) + 1', { a: undefined, b: 5 }) // '6'
// 第一个值有效,直接使用
calc('(a | b) * 2', { a: 3, b: 100 }) // '6'
// 三个路径
calc('(a | b | c) + 1', { a: null, b: undefined, c: 7 }) // '8'复杂路径
支持对象属性路径、数组索引等复杂路径:
javascript
// 对象属性路径
calc('(obj.a | obj.b) * 2', {
obj: { a: null, b: 4 }
}) // '8'
// 数组索引路径
calc('(arr[0] | arr[1]) + 5', {
arr: [null, 10]
}) // '15'
// 复杂嵌套路径
calc('(data.list[0].value | data.default) * 3', {
data: {
list: [{ value: null }],
default: 6
}
}) // '18'与普通变量混用
多路取值可以与普通变量自由组合:
javascript
// 多路取值与普通变量混用
calc('a + (b | c) * d', { a: 1, b: null, c: 2, d: 3 }) // '7'
// 多个多路取值组合
calc('((a | b) + (c | d)) * (e | f)', {
a: null, b: 2,
c: undefined, d: 3,
e: null, f: 4
}) // '20'空值判断
默认情况下,null 和 undefined 被视为空值。你可以通过配置自定义空值判断逻辑。
默认行为
javascript
// null 和 undefined 是空值
calc('(a | b) + 1', { a: null, b: 10 }) // '11'
calc('(a | b) + 1', { a: undefined, b: 5 }) // '6'
// 0 默认不是空值
calc('(a | b) + 1', { a: 0, b: 10 }) // '1'
// 空字符串默认不是空值(但转数字会失败)
calc('(a | b) + 1', { a: '', b: 10, _error: 'ERR' }) // 'ERR'使用 _empty_values
通过 _empty_values 配置,可以自定义哪些值被视为空值:
javascript
// 将 0 视为空值
calc('(a | b) + 1', {
a: 0,
b: 10,
_empty_values: [null, undefined, 0]
}) // '11'
// 将空字符串视为空值
calc('(a | b) + 1', {
a: '',
b: 5,
_empty_values: [null, undefined, '']
}) // '6'
// 将 NaN 视为空值
calc('(a | b) + 1', {
a: NaN,
b: 7,
_empty_values: [null, undefined, NaN]
}) // '8'
// 多个空值类型
calc('(a | b | c) + 1', {
a: null,
b: 0,
c: 10,
_empty_values: [null, undefined, 0, '']
}) // '11'使用 _empty_check
通过 _empty_check 配置,可以自定义空值判断函数,实现更灵活的逻辑:
javascript
// 负数视为空值
calc('(a | b) + 1', {
a: -1,
b: 10,
_empty_check: (value) => value < 0
}) // '11'
// 特定字符串视为空值
calc('(a | b) + 1', {
a: 'N/A',
b: 10,
_empty_check: (value) => value === 'N/A' || value === null || value === undefined
}) // '11'
// 根据路径和值综合判断
calc('(price | defaultPrice) * quantity', {
price: 0,
defaultPrice: 100,
quantity: 2,
_empty_check: (value, path) => {
// 价格为 0 视为空值
if (path.includes('price')) return value <= 0
return value === null || value === undefined
}
}) // '200'优先级
_empty_check 的优先级高于 _empty_values。如果同时配置了两者,只会使用 _empty_check。
与其他特性组合
与格式化组合
javascript
// 带格式化
calc('(a | b) + 0.123 | =2', { a: null, b: 1 }) // '1.12'
// 千分位格式化
calc('(a | b) * 1000 | ,', { a: null, b: 1234 }) // '1,234,000'
// 百分比格式化
calc('(a | b) | %', { a: null, b: 0.5 }) // '50%'与单位计算组合
javascript
// 带单位
calc('(a | b) + 1', {
_unit: true,
a: null,
b: '5元'
}) // '6元'
// 单位转换
calc('(price | defaultPrice) | !ua:元', {
price: null,
defaultPrice: 100
}) // '100元'与解析模式组合
javascript
// space 模式
calc('(a | b) + 1', {
_mode: 'space',
a: null,
b: 8
}) // '9'
// space-all 模式
calc('(a | b) + 1 | =2', {
_mode: 'space-all',
a: null,
b: 8
}) // '9.00'与函数组合
javascript
// 函数参数使用多路取值
calc('sqrt((a | b))', { a: null, b: 16 }) // '4'
// 多路取值结果作为函数参数
calc('max((a | b), (c | d))', {
a: null, b: 10,
c: undefined, d: 5
}) // '10'错误处理
当所有路径都是空值时,会抛出错误:
javascript
// 所有路径都是 null,使用 _error 返回默认值
calc('(a | b | c) + 1', {
a: null,
b: null,
c: null,
_error: 'EMPTY'
}) // 'EMPTY'
// 所有路径都不存在
calc('(a | b) + 1', {
_error: 'EMPTY'
}) // 'EMPTY'
// 不设置 _error 会抛出异常
calc('(a | b) + 1', { a: null, b: null })
// Error: 多路取值失败,所有路径均为空值: a | b实际应用场景
场景一:多数据源优先级
javascript
// 优先使用用户设置,其次使用系统配置,最后使用默认值
const data = {
userConfig: { precision: null },
systemConfig: { precision: 4 },
default: { precision: 2 }
}
calc('(userConfig.precision | systemConfig.precision | default.precision)', data)
// '4'场景二:价格展示
javascript
// 优先展示促销价,没有则展示原价
const product = {
salePrice: null,
originalPrice: 199
}
calc('(salePrice | originalPrice) | =2,', product)
// '199.00'场景三:统计数据处理
javascript
// 处理可能缺失的统计数据
const stats = {
current: { value: null },
previous: { value: 100 },
baseline: 0
}
calc('((current.value | previous.value | baseline) - baseline) / baseline * 100 | =2%', {
...stats,
_empty_values: [null, undefined]
})
// '100.00%'场景四:表单默认值
javascript
// 表单字段:用户输入 > 历史值 > 默认值
const form = {
input: '',
history: 50,
default: 10,
_empty_values: [null, undefined, '']
}
calc('(input | history | default)', form)
// '50'注意事项
- 括号必需:多路取值语法必须用括号包裹
(a | b) - 管道符含义:在多路取值上下文中,
|表示备选路径,而非格式化分隔符 - 空值概念:默认只有
null和undefined是空值,其他值(如0、''、false)默认不是空值 - 性能考虑:多路取值会按顺序尝试每个路径,路径过多可能影响性能
- 错误传播:所有路径都是空值时会抛出错误,建议配合
_error使用