Skip to content

逻辑运算符

a-calc 3.x 引入了完整的逻辑运算符支持,包括与、或、非运算,并实现了短路求值。

支持的运算符

运算符名称含义示例
&&逻辑与两个条件都为真时返回真true && truetrue
||逻辑或任一条件为真时返回真false || truetrue
!逻辑非取反!falsetrue

基本用法

逻辑与 (&&)

javascript
import { calc } from 'a-calc'

// 布尔值运算
calc('true && true')   // true
calc('true && false')  // false
calc('false && true')  // false
calc('false && false') // false

// 与比较运算组合
calc('5 > 3 && 2 > 1')  // true
calc('5 > 3 && 2 < 1')  // false

// 使用变量
calc('x > 0 && y > 0', { x: 5, y: 3 })  // true

逻辑或 (||)

javascript
// 布尔值运算
calc('true || true')   // true
calc('true || false')  // true
calc('false || true')  // true
calc('false || false') // false

// 与比较运算组合
calc('5 < 3 || 2 > 1')  // true
calc('5 < 3 || 2 < 1')  // false

// 使用变量
calc('x < 0 || y < 0', { x: -5, y: 3 })  // true

逻辑非 (!)

javascript
// 基本取反
calc('!true')   // false
calc('!false')  // true

// 与比较运算组合
calc('!(5 > 3)')  // false
calc('!(5 < 3)')  // true

// 双重否定
calc('!!true')   // true
calc('!!false')  // false

短路求值

逻辑运算符实现了短路求值(Short-circuit Evaluation),可以避免不必要的计算:

&& 的短路

&& 左侧为假时,右侧不会被计算:

javascript
// 左侧为假,右侧不执行
calc('false && (1/0 > 0)')  // false(不会触发除零错误)

// 实际应用:安全的条件检查
calc('x != 0 && 10/x > 1', { x: 0 })  // false(避免除零)

|| 的短路

|| 左侧为真时,右侧不会被计算:

javascript
// 左侧为真,右侧不执行
calc('true || (1/0 > 0)')  // true(不会触发除零错误)

// 实际应用:默认值模式
calc('x > 0 || y > 0', { x: 5, y: 'invalid' })  // true(y 不会被计算)

真值判断规则

逻辑运算符会将操作数转换为布尔值,转换规则如下:

值类型假值 (false)真值 (true)
布尔值falsetrue
数字0非零数字
字符串"""0"其他字符串
Decimal0非零
javascript
// 数字作为布尔值
calc('0 && true')   // false(0 为假)
calc('1 && true')   // true(1 为真)
calc('0 || true')   // true
calc('1 || false')  // true

// 字符串作为布尔值
calc('"" || true')   // true(空字符串为假)
calc('"0" || true')  // true("0" 字符串为假)
calc('"a" && true')  // true(非空非"0"字符串为真)

组合使用

多条件组合

javascript
// 多个 && 组合
calc('a > 0 && b > 0 && c > 0', { a: 1, b: 2, c: 3 })  // true
calc('a > 0 && b > 0 && c > 0', { a: 1, b: 0, c: 3 })  // false

// 多个 || 组合
calc('a < 0 || b < 0 || c < 0', { a: 1, b: -1, c: 3 })  // true

// && 和 || 混合
calc('(a > 0 && b > 0) || c > 0', { a: -1, b: -1, c: 5 })  // true
calc('a > 0 && (b > 0 || c > 0)', { a: 1, b: -1, c: 5 })   // true

与条件表达式组合

javascript
// 逻辑运算作为条件
calc('(x > 0 && y > 0) ? x + y : 0', { x: 3, y: 4 })  // '7'
calc('(x > 0 || y > 0) ? 1 : 0', { x: -1, y: 2 })     // '1'

// 复杂条件
calc('(!invalid && value > 0) ? value : defaultVal', {
    invalid: false,
    value: 100,
    defaultVal: 0
})  // '100'

与函数组合

javascript
// 函数结果参与逻辑运算
calc('sqrt(x) > 0 && abs(y) < 10', { x: 16, y: -5 })  // true

// 条件执行函数
calc('x > 0 ? sqrt(x) : abs(x)', { x: -16 })  // '16'

运算符优先级

逻辑运算符的优先级如下(从高到低):

运算符优先级结合性
!9右结合
&&3左结合
||2左结合
javascript
// ! 优先级最高
calc('!true && false')  // false(等价于 (!true) && false)
calc('!(true && false)') // true(使用括号改变优先级)

// && 优先级高于 ||
calc('true || false && false')   // true(等价于 true || (false && false))
calc('(true || false) && false') // false(使用括号改变优先级)

实际应用示例

表单验证

javascript
// 多条件验证
const validateForm = (data) => calc(`
    name != "" &&
    age >= 18 &&
    age <= 100 &&
    email != ""
`, data)

validateForm({ name: 'John', age: 25, email: 'john@example.com' })  // true
validateForm({ name: '', age: 25, email: 'john@example.com' })      // false

权限检查

javascript
// 检查用户权限
const hasAccess = (user) => calc(`
    (role == "admin") ||
    (role == "editor" && department == targetDept)
`, { ...user, targetDept: 'IT' })

hasAccess({ role: 'admin', department: 'HR' })     // true
hasAccess({ role: 'editor', department: 'IT' })    // true
hasAccess({ role: 'editor', department: 'HR' })    // false
hasAccess({ role: 'viewer', department: 'IT' })    // false

商品可购买判断

javascript
// 判断商品是否可购买
const canBuy = (product, user) => calc(`
    stock > 0 &&
    !disabled &&
    (price <= budget || isVip)
`, { ...product, ...user })

canBuy(
    { stock: 10, disabled: false, price: 100 },
    { budget: 80, isVip: true }
)  // true(VIP可以超预算购买)

canBuy(
    { stock: 0, disabled: false, price: 50 },
    { budget: 100, isVip: false }
)  // false(无库存)

日期范围检查

javascript
// 检查是否在有效期内
const isValid = (item) => calc(`
    currentTime >= startTime &&
    currentTime <= endTime &&
    !expired
`, item)

isValid({
    currentTime: 1000,
    startTime: 500,
    endTime: 1500,
    expired: false
})  // true

注意事项

  1. 短路求值:利用短路特性可以避免不必要的计算和潜在错误
  2. 类型转换:非布尔值会按规则转换,注意 "0" 字符串被视为假值
  3. 优先级:复杂表达式建议使用括号明确优先级
  4. 与格式化:逻辑运算返回布尔值,格式化参数会被忽略
  5. || 与 |:注意 || 是逻辑或运算符,单个 | 是格式化分隔符

基于 MIT 许可发布