In Jurassic Park, security protocols must be strictly followed and executed in the proper order. For example, before opening the gate to the Tyrannosaurus enclosure, you must ensure that all other doors are closed and that employees are in safe zones. The order of these actions is crucial.
Similarly in JavaScript, operators have their precedence, which determines the order of their execution in expressions. Understanding this hierarchy is essential for creating correct and predictable expressions.
Operator precedence is a rule that determines the order in which operators are executed in complex expressions. Operators with higher precedence are executed before operators with lower precedence.
Imagine that in Jurassic Park we have a task list with different priorities:
Similarly, JavaScript has its own hierarchy of operator precedence.
Below is a simplified table of operator precedence in JavaScript, from highest to lowest:
| Precedence | Category | Operators | |-----------|----------|-----------| | 19 | Grouping | ( ... ) | | 18 | Property access and array elements | . [] ?. | | 17 | Function call | ... ( ... ) | | 16 | Postfix operators | ++ -- | | 15 | Prefix operators | ! ~ + - ++ -- typeof void delete | | 14 | Exponentiation | ** | | 13 | Multiplication, division, modulo | * / % | | 12 | Addition, subtraction | + - | | 11 | Bitwise shift | << >> >>> | | 10 | Comparisons (inequalities) | < > <= >= instanceof in | | 9 | Equality | == != === !== | | 8 | Bitwise AND | & | | 7 | Bitwise XOR | ^ | | 6 | Bitwise OR | | | | 5 | Logical AND | && | | 4 | Logical OR | || | | 3 | Nullish coalescing | ?? | | 2 | Conditional operator | ? : | | 1 | Assignment | = += -= *= /= %= <<= >>= >>>= &= ^= |= **= | | 0 | Comma operator | , |
Let's see how operator precedence works in practice, using examples from daily work in Jurassic Park:
1// Calculating the amount of food needed for dinosaurs
2
3let smallCarnivores = 5;
4let mediumCarnivores = 3;
5let largeCarnivores = 2;
6
7let dailyConsumptionSmall = 50; // kg
8let dailyConsumptionMedium = 150; // kg
9let dailyConsumptionLarge = 300; // kg
10
11// Without parentheses - operator precedence determines the order
12let totalFood = smallCarnivores * dailyConsumptionSmall + mediumCarnivores * dailyConsumptionMedium + largeCarnivores * dailyConsumptionLarge;
13
14console.log(totalFood); // 1150 kg
15
16// Multiplication (*) has higher precedence than addition (+), so the above expression is equivalent to:
17let totalFood2 = (smallCarnivores * dailyConsumptionSmall) + (mediumCarnivores * dailyConsumptionMedium) + (largeCarnivores * dailyConsumptionLarge);
18
19console.log(totalFood2); // 1150 kg (same result)1// Checking conditions for opening an enclosure to visitors
2
3let airTemperature = 28; // degrees Celsius
4let humidity = 60; // percent
5let windSpeed = 15; // km/h
6let threatLevel = 2; // scale 1-5
7let availableStaff = 5; // number of employees
8let requiredStaff = 3; // minimum number
9
10// Complex condition without parentheses
11let openEnclosure = airTemperature > 20 && humidity < 80 && windSpeed < 20 || threatLevel <= 2 && availableStaff >= requiredStaff;
12
13// How does JavaScript interpret this? The && operator has higher precedence than ||
14// The above expression is equivalent to:
15let openEnclosure2 = ((airTemperature > 20 && humidity < 80 && windSpeed < 20) || (threatLevel <= 2 && availableStaff >= requiredStaff));
16
17console.log(openEnclosure); // true
18console.log(openEnclosure2); // true (same result)1// Determining security status for different dinosaur species
2
3let species = "Velociraptor";
4let aggression = 4; // scale 1-5
5let fenceHeight = 5; // meters
6
7// Complex expression with conditional operator and assignment
8let securityStatus = species === "Tyrannosaurus" || species === "Spinosaurus" || aggression >= 4 ? "High" : aggression >= 3 ? "Medium" : "Low";
9
10console.log(securityStatus); // "High" (for Velociraptor with aggression 4)
11
12// More readable version with parentheses showing the actual evaluation order:
13let securityStatus2 = (species === "Tyrannosaurus" || species === "Spinosaurus" || aggression >= 4) ? "High" : (aggression >= 3 ? "Medium" : "Low");
14
15console.log(securityStatus2); // "High" (same result)1// Calculating estimated dinosaur population after several generations
2
3let initialPopulation = 2;
4let reproductionRate = 3; // average number of offspring
5let generations = 2;
6
7// Calculation without parentheses
8let estimatedPopulation1 = initialPopulation * reproductionRate ** generations;
9console.log(estimatedPopulation1); // 18 (2 * 3^2 = 2 * 9 = 18)
10
11// Changing the order using parentheses (grouping)
12let estimatedPopulation2 = (initialPopulation * reproductionRate) ** generations;
13console.log(estimatedPopulation2); // 36 ((2 * 3)^2 = 6^2 = 36)1// Supply calculator after delivery
2
3let currentResources = 500; // kg
4let weeklyDelivery = 200; // kg
5let averageDailyConsumption = 50; // kg
6let daysInWeek = 7;
7let refrigeratorsWorking = true;
8let maxStorageCapacity = 1000; // kg
9
10// Complex calculator without explicit grouping
11let newState = currentResources + weeklyDelivery - averageDailyConsumption * daysInWeek * (refrigeratorsWorking ? 1 : 1.5);
12
13console.log(newState); // 350 kg (500 + 200 - 50 * 7 * 1)
14
15// More readable version with parentheses showing the actual evaluation order:
16let newState2 = currentResources + weeklyDelivery - (averageDailyConsumption * daysInWeek * (refrigeratorsWorking ? 1 : 1.5));
17
18console.log(newState2); // 350 kg (same result)
19
20// Check if the new state exceeds the storage capacity
21let percentageState = newState / maxStorageCapacity * 100;
22console.log(percentageState + "%"); // 35%Although JavaScript has strictly defined operator precedence, using parentheses to explicitly define the order of operations has several advantages:
Increases code readability - even if you know operator precedence, explicit parentheses make code more readable for you and others.
Prevents errors - in complex expressions, it's easy to make mistakes related to the order of operations.
Facilitates modification - if you later change an expression, parentheses can prevent unexpected changes in logic.
1// Example of using parentheses for increased readability
2
3// Less readable:
4let isSafe = !fenceBroken && powerActive || emergencyMode && evacuationComplete;
5
6// More readable with parentheses:
7let isSafe2 = (!fenceBroken && powerActive) || (emergencyMode && evacuationComplete);Besides precedence, an important characteristic of operators is their associativity, which determines the order of execution for operators of the same precedence:
+, -, *, /=, **, +=, unary operators (!, ++, --)1// Example of left-to-right associativity
2let a = 5 - 3 - 2; // (5 - 3) - 2 = 0
3
4// Example of right-to-left associativity
5let b = 2;
6let c = 3;
7let d = 4;
8let e = b = c = d; // b = (c = (d)) = 4
9console.log(b, c, d, e); // 4, 4, 4, 4
10
11// Exponentiation is also right-to-left associative
12let f = 2 ** 3 ** 2; // 2 ** (3 ** 2) = 2 ** 9 = 512
13let g = (2 ** 3) ** 2; // 8 ** 2 = 64
14console.log(f, g); // 512, 64In Jurassic Park, ambiguity in security protocols can lead to catastrophic consequences. Similarly, ambiguous expressions in code can lead to unexpected results. Here are some tips:
Use parentheses when combining different types of operators - especially when mixing arithmetic, logical, and conditional operators.
Break complex expressions into simpler ones - for greater readability and easier debugging, you can assign intermediate results to variables.
1// Instead of:
2let result = a * b + c * d && e > f || g <= h;
3
4// Better:
5let part1 = a * b + c * d;
6let part2 = e > f;
7let part3 = g <= h;
8let result = part1 && part2 || part3;++ and -- operators can lead to unexpected results when used in complex expressions.1let dinosaurCount = 5;
2let newCount = dinosaurCount++ * 2; // first uses value 5, then increments dinosaurCount to 6
3console.log(newCount, dinosaurCount); // 10, 6
4
5let cageCount = 5;
6let newCageCount = ++cageCount * 2; // first increments cageCount to 6, then uses that value
7console.log(newCageCount, cageCount); // 12, 6Operator precedence in JavaScript, much like the task hierarchy in Jurassic Park, determines the order of operations. Knowledge of this hierarchy is crucial for writing correct and predictable code.
The most important things to remember:
Remember, when in doubt, it's always better to use parentheses for clarity - just as in Jurassic Park, where it's better to over-protect against unexpected situations than to risk unforeseen consequences.
In the next lesson, we will look at control structures - conditional statements that allow making decisions based on specific conditions - essential for managing such a complex undertaking as Jurassic Park.