Skip to content

JEXL Operators

JEXL provides a comprehensive set of operators for performing calculations, comparisons, logical operations, and data transformations. Understanding operator precedence and behavior is essential for writing correct expressions.

Arithmetic Operators

Perform mathematical calculations on numbers.

Addition (+)

javascript
5 + 3           // 8
1.5 + 2.5       // 4.0
-10 + 5         // -5

// String concatenation
"Hello" + " " + "World"    // "Hello World"
"Score: " + 95             // "Score: 95"

Subtraction (-)

javascript
10 - 3          // 7
5.5 - 2.2       // 3.3
0 - 5           // -5

Multiplication (*)

javascript
4 * 3           // 12
2.5 * 4         // 10.0
-3 * 2          // -6

Division (/)

javascript
10 / 2          // 5
7 / 3           // 2.333...
10 / 0          // Infinity

Modulus (%)

javascript
10 % 3          // 1
7 % 2           // 1
12 % 4          // 0

Exponentiation (^)

javascript
2 ^ 3           // 8
4 ^ 0.5         // 2 (square root)
10 ^ 2          // 100

Unary Minus (-)

javascript
-5              // -5
-(3 + 2)        // -5
-(-5)           // 5

Comparison Operators

Compare values and return boolean results.

Equality (==)

javascript
5 == 5          // true
"hello" == "hello"    // true
true == true    // true
5 == "5"        // true (type coercion)
null == null    // true

Inequality (!=)

javascript
5 != 3          // true
"a" != "b"      // true
true != false   // true
5 != "5"        // false (type coercion)

Less Than (<)

javascript
3 < 5           // true
"a" < "b"       // true (lexicographic)
10 < 10         // false

Less Than or Equal (<=)

javascript
3 <= 5          // true
5 <= 5          // true
10 <= 9         // false

Greater Than (>)

javascript
5 > 3           // true
"b" > "a"       // true
10 > 10         // false

Greater Than or Equal (>=)

javascript
5 >= 3          // true
5 >= 5          // true
3 >= 5          // false

Logical Operators

Perform logical operations and combine boolean expressions.

Logical AND (&&)

javascript
true && true           // true
true && false          // false
false && true          // false
false && false         // false

// Short-circuit evaluation
age >= 18 && hasLicense     // Only checks hasLicense if age >= 18
user && user.name           // Safe property access

Logical OR (||)

javascript
true || true           // true
true || false          // true
false || true          // true
false || false         // false

// Default values
name || "Anonymous"    // Use "Anonymous" if name is falsy
config.timeout || 5000 // Default timeout

Logical NOT (!)

javascript
!true              // false
!false             // true
!"hello"           // false (truthy string)
!""                // true (empty string is falsy)
!0                 // true (zero is falsy)
!null              // true (null is falsy)

Membership Operator

Test if a value exists within another value.

In Operator (in)

javascript
// Array membership
"apple" in ["apple", "banana", "orange"]     // true
5 in [1, 2, 3, 4, 5]                        // true

// Object property existence
"name" in {name: "John", age: 30}           // true
"email" in {name: "John", age: 30}          // false

// String substring
"ell" in "hello"                            // true
"xyz" in "hello"                            // false

Conditional (Ternary) Operator

Provide conditional logic with the ? : operator.

Basic Ternary (? :)

javascript
age >= 18 ? "adult" : "minor"
score >= 60 ? "pass" : "fail"
user ? user.name : "Guest"

Nested Ternary

javascript
// Grade calculation
score >= 90 ? "A" :
score >= 80 ? "B" :
score >= 70 ? "C" :
score >= 60 ? "D" : "F"

// Status determination
errors > 0 ? "error" :
warnings > 0 ? "warning" : "success"

Transform (Pipe) Operator

Apply functions to values using the pipe operator (|).

Basic Transforms

javascript
"hello" | uppercase           // "HELLO"
[1, 2, 3] | length           // 3
"  text  " | trim            // "text"

Chained Transforms

javascript
// String processing
"  Hello World  " | trim | lowercase | split(" ") | join("-")
// Result: "hello-world"

// Array processing
[1, 2, 3, 4, 5] | filter("value > 2") | map("value * 2") | sum
// Result: 24 (sum of [6, 8, 10])

Transforms with Arguments

javascript
"hello world" | substring(0, 5)        // "hello"
[1, 2, 3] | map("value * " + multiplier)  // Multiply by variable
users | filter("value.age > " + minAge)   // Filter with variable

Property Access Operators

Access properties and array elements.

Dot Notation (.)

javascript
user.name              // Simple property
user.profile.email     // Nested property
config.database.host   // Deep nesting

Bracket Notation ([])

javascript
user["name"]           // Property access
user[propertyName]     // Dynamic property
array[0]               // Array index
array[index]           // Dynamic index
array[-1]              // Negative index (last element)

Operator Precedence

Operators are evaluated in the following order (highest to lowest precedence):

PrecedenceOperatorsDescriptionAssociativity
1. [] ()Property access, function callsLeft-to-right
2! - (unary)Logical NOT, unary minusRight-to-left
3^ExponentiationRight-to-left
4* / %Multiplication, division, modulusLeft-to-right
5+ -Addition, subtractionLeft-to-right
6< <= > >=ComparisonLeft-to-right
7== !=EqualityLeft-to-right
8inMembershipLeft-to-right
9&&Logical ANDLeft-to-right
10||Logical ORLeft-to-right
11? :Ternary conditionalRight-to-left
12|Transform (pipe)Left-to-right

Precedence Examples

javascript
// Arithmetic precedence
2 + 3 * 4        // 14, not 20 (multiplication first)
(2 + 3) * 4      // 20 (parentheses override)

// Comparison and logical precedence
age > 18 && hasLicense    // Comparison first, then AND
!(age > 18)               // NOT applied to comparison result

// Transform precedence
users | length > 0        // Transform first: (users | length) > 0
users | (length > 0)      // Would be invalid syntax

Associativity

When operators have the same precedence, associativity determines evaluation order.

Left-to-right (Left Associative)

javascript
10 - 5 - 2       // (10 - 5) - 2 = 3
a | b | c        // (a | b) | c

Right-to-left (Right Associative)

javascript
2 ^ 3 ^ 2        // 2 ^ (3 ^ 2) = 2 ^ 9 = 512
a ? b : c ? d : e // a ? b : (c ? d : e)

Operator Overloading

Some operators work differently based on operand types.

Addition (+)

javascript
// Numeric addition
5 + 3            // 8

// String concatenation
"Hello" + " World"    // "Hello World"

// Mixed types (converts to string)
"Count: " + 5    // "Count: 5"

Comparison with Type Coercion

javascript
// Numeric comparison
5 > 3            // true

// String comparison (lexicographic)
"b" > "a"        // true
"10" > "2"       // false (string comparison)

// Mixed type comparison
"10" > 2         // true (converts to number)

Best Practices

1. Use Parentheses for Clarity

javascript
// Good - clear intent
(score >= 90) && (attendance >= 0.8)

// Less clear - relies on precedence
score >= 90 && attendance >= 0.8

2. Avoid Complex Precedence Mixing

javascript
// Good - explicit grouping
result = (a + b) * (c - d)

// Harder to read
result = a + b * c - d

3. Use Meaningful Variable Names in Complex Expressions

javascript
// Good
isEligibleStudent = (age >= 18) && (gpa >= 3.0) && (creditsCompleted >= 60)

// Less readable  
result = a >= 18 && b >= 3.0 && c >= 60

4. Break Down Complex Ternary Operations

javascript
// Good - readable chain
grade = score >= 90 ? "A" :
        score >= 80 ? "B" :
        score >= 70 ? "C" :
        score >= 60 ? "D" : "F"

// Harder to read - nested ternary
grade = score >= 90 ? "A" : (score >= 80 ? "B" : (score >= 70 ? "C" : (score >= 60 ? "D" : "F")))

5. Use Short-Circuit Evaluation Safely

javascript
// Good - safe property access
user && user.profile && user.profile.email

// Good - provide defaults
config.timeout || 5000

// Be careful with falsy values
count || 0  // Wrong if count should be 0
count != null ? count : 0  // Safer

Common Patterns

Safe Navigation

javascript
// Check existence before access
user && user.address && user.address.city

// Using in operator
"address" in user && "city" in user.address ? user.address.city : null

Default Value Assignment

javascript
// Simple defaults
name = inputName || "Anonymous"
timeout = config.timeout || 5000

// More specific defaults
port = config.port != null ? config.port : 3000

Range Checks

javascript
// Age range
isValidAge = age >= 0 && age <= 120

// Score range
isValidScore = score >= 0 && score <= 100

Type Checking with Operations

javascript
// Check if numeric
isNumber = typeof value == "number" && !isNaN(value)

// Check if non-empty string
isValidString = typeof value == "string" && value.length > 0

Next: Learn how to build complex JEXL Expressions using these operators.

Released under the MIT License.