Operators

Complete reference for all JEXL operators including precedence and usage examples

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 (+)

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

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

Subtraction (-)

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

Multiplication (*)

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

Division (/)

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

Modulus (%)

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

Exponentiation (^)

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

Unary Minus (-)

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

Comparison Operators

Compare values and return boolean results.

Equality (==)

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

Inequality (!=)

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

Less Than (<)

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

Less Than or Equal (<=)

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

Greater Than (>)

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

Greater Than or Equal (>=)

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

Logical Operators

Perform logical operations and combine boolean expressions.

Logical AND (&&)

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 (||)

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 (!)

!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)

// 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 (? :)

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

Nested Ternary

// 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

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

Chained Transforms

// 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

"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 (.)

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

Bracket Notation ([])

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

// 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)

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

Right-to-left (Right Associative)

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 (+)

// Numeric addition
5 + 3            // 8

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

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

Comparison with Type Coercion

// 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

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

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

2. Avoid Complex Precedence Mixing

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

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

3. Use Meaningful Variable Names in Complex Expressions

// 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

// 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

// 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

// 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

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

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

Range Checks

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

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

Type Checking with Operations

// 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.

Cookie Notice

We use cookies to enhance your browsing experience.