In the previous lesson you learned to store the data of a Taller Nómada task in variables of the right type. Storing is fine, but a program that calculates nothing is not much use. Operators are the symbols that combine and transform values: adding up hours, working out percentages, deciding whether a condition holds, or supplying a default value when a piece of data is missing. In this lesson you will go through all of them —from the humble + to the modern ?? and ?.— and you will end up calculating the real workload of Marta, Iván and Lucía.
Contents
- Arithmetic operators
- Increment and decrement: prefix and postfix
- Assignment operators
- Logical operators and short-circuiting
- Nullish coalescing:
??and??= - Optional chaining:
?. - The ternary operator
? : - Concatenation versus template literals
- Operator precedence
- Application: the team's hourly workload
- Common Mistakes and Tips
- Exercises
- Conclusion
- Arithmetic operators
These are the ones that do numeric calculations.
| Operator | Name | Example | Result |
|---|---|---|---|
+ |
Addition | 12 + 8 |
20 |
- |
Subtraction | 12 - 8 |
4 |
* |
Multiplication | 12 * 2 |
24 |
/ |
Division | 12 / 8 |
1.5 |
% |
Modulo (remainder) | 12 % 8 |
4 |
** |
Exponentiation | 2 ** 3 |
8 |
const ivanHours = 12;
const luciaHours = 8;
console.log(ivanHours + luciaHours); // 20
console.log(ivanHours - luciaHours); // 4
console.log(ivanHours / luciaHours); // 1.5
console.log(ivanHours % luciaHours); // 41.1 Modulo % is more useful than it looks
% returns the remainder of an integer division. Its two classic uses:
Finding out whether a number is even or odd:
const taskNumber = 7;
console.log(taskNumber % 2); // 1 → odd
console.log(taskNumber % 2 === 0); // falseDistributing in cycles. In Nómada Tasks we will use it to assign tasks in rotation among the three people on the team:
// The team has 3 people: positions 0, 1 and 2
console.log(0 % 3); // 0 → Marta
console.log(1 % 3); // 1 → Iván
console.log(2 % 3); // 2 → Lucía
console.log(3 % 3); // 0 → Marta again
console.log(4 % 3); // 1 → IvánThe remainder of dividing by 3 is always 0, 1 or 2: exactly the team's positions, cyclically.
1.2 Division never fails
In many languages, dividing by zero raises an error. In JavaScript it does not:
This is dangerous because the program does not stop: it keeps calculating with Infinity or NaN and the error surfaces much later, somewhere completely unrelated.
const completedTasks = 5;
const totalTasks = 0; // there are no tasks yet!
const percentage = (completedTasks / totalTasks) * 100;
console.log(percentage); // Infinity — not an error, but wrongThe fix is to check the divisor before dividing, something you will do comfortably once you learn conditionals in Module 2.
1.3 + has a split personality
Here comes the first big trap. + is both addition and string concatenation:
console.log(12 + 8); // 20 → numeric addition
console.log('12' + '8'); // '128' → string concatenation
console.log('12' + 8); // '128' → if one of them is text, it concatenates!
console.log(12 + '8'); // '128'The rule is merciless: if either operand is a string, + concatenates. This behavior is the number-one cause of wrong calculations among beginners, especially with data coming from a form (where everything arrives as text).
The other arithmetic operators do not have this problem: they try to convert to a number.
console.log('12' - 8); // 4 → converts '12' to a number
console.log('12' * 2); // 24
console.log('12' / 2); // 6
console.log('high' * 2); // NaN → cannot be convertedIn Type Conversion and Comparisons you will see exactly why this happens and how to protect yourself.
- Increment and decrement: prefix and postfix
++ adds 1 and -- subtracts 1 from a variable.
let completedTasks = 5;
completedTasks++;
console.log(completedTasks); // 6
completedTasks--;
console.log(completedTasks); // 5Both have two forms, and the difference matters only when you use the result in the same expression:
| Form | Name | What it does |
|---|---|---|
x++ |
Postfix | Returns the old value and then increments |
++x |
Prefix | Increments and then returns the new value |
let a = 5;
console.log(a++); // 5 ← returns the old value
console.log(a); // 6 ← but it has already been incremented
let b = 5;
console.log(++b); // 6 ← increments first
console.log(b); // 6A mnemonic: ++ acts at the position where it is written. If it comes first, it increments first; if it comes after, it returns first.
Practical tip: use ++ and -- on lines of their own, never inside complex expressions. That kind of code is an inexhaustible source of bugs:
- Assignment operators
= assigns a value. The rest combine an operation with the assignment:
| Operator | Equivalent to | Example | Result (starting from h = 12) |
|---|---|---|---|
= |
— | h = 8 |
8 |
+= |
h = h + 8 |
h += 8 |
20 |
-= |
h = h - 8 |
h -= 8 |
4 |
*= |
h = h * 2 |
h *= 2 |
24 |
/= |
h = h / 4 |
h /= 4 |
3 |
%= |
h = h % 5 |
h %= 5 |
2 |
**= |
h = h ** 2 |
h **= 2 |
144 |
let accumulatedHours = 0;
accumulatedHours += 12; // Iván's task
accumulatedHours += 8; // Lucía's task
accumulatedHours += 6; // Marta's task
console.log(accumulatedHours); // 26+= also works with text, for the same reason + does:
let summary = 'Team: ';
summary += 'Marta, ';
summary += 'Iván, ';
summary += 'Lucía';
console.log(summary); // Team: Marta, Iván, LucíaRemember that variables assigned with these operators have to be declared with let: with const you would get a TypeError.
- Logical operators and short-circuiting
There are three of them, and they hide behavior that is worth understanding properly.
| Operator | Name | Informal meaning |
|---|---|---|
&& |
Logical AND | Both must hold |
|| |
Logical OR | One of them holding is enough |
! |
NOT | Inverts the logical value |
const isUrgent = true;
const isAssigned = false;
console.log(isUrgent && isAssigned); // false
console.log(isUrgent || isAssigned); // true
console.log(!isUrgent); // false4.1 Short-circuit evaluation
JavaScript evaluates these operators from left to right and stops as soon as it knows the result:
- With
&&: if the first value is false, the result is already false. It does not evaluate the second. - With
||: if the first value is true, the result is already true. It does not evaluate the second.
function notify() {
console.log('Notification sent to Marta');
return true;
}
false && notify(); // Prints nothing: it stops at the false
true || notify(); // Prints nothing: it stops at the true
true && notify(); // Prints 'Notification sent to Marta'This is used all the time as shorthand for "do this only if that holds":
4.2 What they actually return
Here is the detail almost nobody explains: && and || do not return true or false. They return one of the operands.
a || breturnsaifais truthy; otherwise it returnsb.a && breturnsaifais falsy; otherwise it returnsb.
console.log('Iván' || 'unassigned'); // 'Iván'
console.log('' || 'unassigned'); // 'unassigned'
console.log(0 || 40); // 40
console.log('high' && 'medium'); // 'medium'
console.log(null && 'medium'); // null(The concepts truthy and falsy —which values count as true or false without actually being booleans— are covered in the next lesson. For now it is enough to know that 0, '', null, undefined and NaN are falsy, and practically everything else is truthy.)
This behavior enables the classic default value pattern:
const receivedAssignee = '';
const assignee = receivedAssignee || 'Unassigned';
console.log(assignee); // 'Unassigned'But be careful: there is an important trap.
const receivedHours = 0; // 0 is a legitimate value!
const hours = receivedHours || 8;
console.log(hours); // 8 ← wrong! We wanted 0Since 0 is falsy, || discards it. ?? was created to solve exactly this.
4.3 The ! operator and the double !!
! inverts the logical value:
Applied twice, !! converts any value into its boolean equivalent:
console.log(!!'Iván'); // true
console.log(!!''); // false
console.log(!!0); // false
console.log(!!12); // true
console.log(!!null); // falseIt is a very widespread trick, although Boolean(value) expresses the same thing more clearly.
- Nullish coalescing:
?? and ??=
?? and ??=The ?? operator (ES2020) returns the right-hand operand only if the left-hand one is null or undefined. Unlike ||, it respects 0, '' and false.
const receivedHours = 0;
console.log(receivedHours || 8); // 8 ← || discards the 0
console.log(receivedHours ?? 8); // 0 ← ?? respects itThe full comparison:
| Left-hand value | value || 'default' |
value ?? 'default' |
|---|---|---|
'Iván' |
'Iván' |
'Iván' |
'' |
'default' |
'' |
0 |
'default' |
0 |
false |
'default' |
false |
NaN |
'default' |
NaN |
null |
'default' |
'default' |
undefined |
'default' |
'default' |
Practical rule: for default values, use ??. Use || only when you deliberately want to treat 0 and the empty string as "no value" too.
flowchart TD
A["You need a<br/>default value"] --> B{"Are 0, false<br/>and the empty string<br/>valid data?"}
B -->|"Yes (hours, counters)"| C["Use ??<br/>it only acts on<br/>null and undefined"]
B -->|"No (names, text)"| D["You can use ||<br/>it acts on any<br/>falsy value"]
C --> E["estimatedHours ?? 8"]
D --> F["assignee || 'Unassigned'"]
const assignee = null;
const estimatedHours = 0;
console.log(assignee ?? 'Unassigned'); // 'Unassigned'
console.log(estimatedHours ?? 8); // 0 — correct5.1 Assignment with ??=
??= assigns a value only if the variable is null or undefined:
let reviewer = null;
reviewer ??= 'Marta';
console.log(reviewer); // 'Marta'
let assignee = 'Lucía';
assignee ??= 'Marta';
console.log(assignee); // 'Lucía' — left aloneIt is equivalent to if (reviewer === null || reviewer === undefined) { reviewer = 'Marta'; }, but on a single line.
There are also ||= and &&= with the same logic applied to truthy/falsy.
5.2 A syntax restriction
You cannot mix ?? with && or || without parentheses: it is a deliberate SyntaxError, designed to avoid ambiguity.
// const x = a || b ?? c; // SyntaxError
const x = (a || b) ?? c; // Correct: the parentheses make the intent clear
- Optional chaining:
?.
?.The ?. operator (ES2020) accesses a property only if the preceding value is neither null nor undefined. If it is, it returns undefined instead of throwing an error.
The problem it solves:
const task = { title: 'Redesign the room', assignee: null };
// console.log(task.assignee.length); // TypeError: Cannot read properties of nullThat TypeError halts the entire program. With ?.:
It can be chained as many times as necessary:
const task = { title: 'Set up the exhibition' };
console.log(task.review?.author); // undefined
console.log(task.review?.author?.name); // undefinedWithout ?., the second line would throw a TypeError the moment task.review was undefined.
It pairs beautifully with ??:
const task = { title: 'Review the invoices', assignee: null };
const name = task.assignee?.name ?? 'Unassigned';
console.log(name); // 'Unassigned'Important warning: ?. is not an excuse for not checking your data. If you put it everywhere, you will hide real bugs instead of fixing them. Use it where it is genuinely legitimate for the value to be missing.
The full use of
?.with nested objects, arrays (task?.tags?.[0]) and function calls (task.save?.()) will be revisited in Module 4, when you work with real objects.
- The ternary operator
? :
? :It is the only JavaScript operator that takes three operands. Its shape:
const estimatedHours = 12;
const taskType = estimatedHours > 8 ? 'long' : 'short';
console.log(taskType); // 'long'It reads like a question: is estimatedHours > 8? Then 'long'; otherwise 'short'.
The big advantage over an if is that the ternary is an expression: it produces a value and can therefore be assigned, passed as an argument or interpolated.
const assignee = 'Marta';
const hours = 6;
console.log(`${assignee} has a ${hours > 8 ? 'long' : 'short'} task`);
// Marta has a short taskThey can be chained, although it is best not to overdo it:
const estimatedHours = 12;
const category =
estimatedHours > 16 ? 'project' :
estimatedHours > 8 ? 'long' :
estimatedHours > 2 ? 'medium' :
'quick';
console.log(category); // 'long'Aligned like that it reads well, but beyond three or four cases a switch or an if/else is better, which you will see in Module 2.
When to use each one:
| Situation | Tool |
|---|---|
| Choosing between two values to assign | Ternary |
| Inserting a decision inside a piece of text | Ternary |
| Running several statements depending on the condition | if/else |
| Many cases over the same value | switch |
- Concatenation versus template literals
You already know the two ways of composing text. Let's put them side by side:
const assignee = 'Iván';
const hours = 12;
const dueDate = '2026-09-30';
// Concatenation with +
const withConcatenation =
'Task for ' + assignee + ': ' + hours + ' h, due on ' + dueDate;
// Template literal
const withTemplate =
`Task for ${assignee}: ${hours} h, due on ${dueDate}`;| Aspect | Concatenation + |
Template literal |
|---|---|---|
| Readability | Low: the text is broken up | High: the text reads as a whole |
| Spaces | Easy to forget | Visible in the text itself |
| Expressions | Require parentheses | ${hours * 2} directly |
| Line breaks | With \n |
Real ones, by pressing Enter |
| Risk of concatenating by accident | High | None: everything is converted to text |
That last point matters. With + you can end up adding by accident:
const ivanHours = 12;
const luciaHours = 8;
console.log('Total: ' + ivanHours + luciaHours); // 'Total: 128' ← wrong!
console.log('Total: ' + (ivanHours + luciaHours)); // 'Total: 20' ← with parentheses
console.log(`Total: ${ivanHours + luciaHours}`); // 'Total: 20' ← no ambiguityUse template literals whenever you combine text and variables. There is no reason not to.
- Operator precedence
When an expression mixes operators, JavaScript applies a fixed order called precedence. From highest to lowest priority, as far as it affects you right now:
| Level | Operators | Associativity | Example |
|---|---|---|---|
| 1 | () grouping |
— | (2 + 3) * 4 → 20 |
| 2 | ?. optional access |
Left | task?.title |
| 3 | ++ -- postfix |
— | i++ |
| 4 | ! ++ -- prefix, typeof |
Right | !isDone |
| 5 | ** |
Right | 2 ** 3 ** 2 → 512 |
| 6 | * / % |
Left | 2 + 3 * 4 → 14 |
| 7 | + - |
Left | 10 - 3 - 2 → 5 |
| 8 | < > <= >= |
Left | 12 > 8 |
| 9 | == != === !== |
Left | 'high' === 'high' |
| 10 | && |
Left | a && b |
| 11 | || and ?? |
Left | a || b |
| 12 | ? : ternary |
Right | x > 0 ? 'yes' : 'no' |
| 13 | = += -= ??= |
Right | x += 1 |
Examples that clarify the rules:
console.log(2 + 3 * 4); // 14, not 20: * binds tighter than +
console.log((2 + 3) * 4); // 20: parentheses win
console.log(10 - 3 - 2); // 5: - is left-associative → (10-3)-2
console.log(2 ** 3 ** 2); // 512: ** is right-associative → 2**(3**2)
console.log(!true && false); // false: ! is applied before &&A realistic case in Nómada Tasks:
const ivanHours = 12;
const luciaHours = 8;
const martaHours = 6;
// The team average: what do you think this gives?
console.log(ivanHours + luciaHours + martaHours / 3); // 22 ← wrong!
console.log((ivanHours + luciaHours + martaHours) / 3); // 8.67 ← correctIn the first case, / is applied before +, so only Marta's hours get divided.
The definitive tip: do not memorize the table. Use parentheses. They cost two characters and remove all doubt, both for the engine and for whoever reads your code. Nobody has ever complained about an extra parenthesis; plenty of bugs come from a missing one.
- Application: the team's hourly workload
Let's bring it all together in a real Taller Nómada scenario. Marta wants to know how the workload is distributed before assigning new tasks.
'use strict';
// --- Starting data ------------------------------------------------
const MAX_WEEKLY_HOURS = 40;
const assignee = 'Iván';
const task1Hours = 12; // Redesign the multipurpose room
const task2Hours = 8; // Signage for the screen-printing workshop
const task3Hours = 4.5; // Review the autumn catalog
// This value might not arrive (for example, if the task has not been estimated yet)
const task4Hours = null;
// --- Calculations --------------------------------------------------
// 1. Assigned hours. With ?? we treat the missing estimate as 0
const assignedHours =
task1Hours + task2Hours + task3Hours + (task4Hours ?? 0);
// 2. Free hours (this could come out negative if the person is overloaded)
const freeHours = MAX_WEEKLY_HOURS - assignedHours;
// 3. Workload percentage, rounded
const workloadPercentage = Math.round((assignedHours / MAX_WEEKLY_HOURS) * 100);
// 4. Workload status with a chained ternary
const workloadStatus =
workloadPercentage >= 100 ? 'overloaded' :
workloadPercentage >= 75 ? 'high' :
workloadPercentage >= 40 ? 'balanced' :
'room to spare';
// 5. Can this person take on a new 8-hour task?
const NEW_TASK_HOURS = 8;
const canTakeIt = freeHours >= NEW_TASK_HOURS;
// --- Output ---------------------------------------------------------
console.log(`=== Weekly workload for ${assignee} ===`);
console.log(`Assigned: ${assignedHours} h of ${MAX_WEEKLY_HOURS} h`);
console.log(`Free: ${freeHours} h`);
console.log(`Workload: ${workloadPercentage}% (${workloadStatus})`);
console.log(
`Can they take on ${NEW_TASK_HOURS} h more? ${canTakeIt ? 'Yes' : 'No'}`
);
// 6. A warning only if the workload is in the danger zone, using short-circuiting
workloadPercentage >= 75 &&
console.warn(`Warning: ${assignee} is at ${workloadPercentage}%`);Output:
=== Weekly workload for Iván === Assigned: 24.5 h of 40 h Free: 15.5 h Workload: 61% (balanced) Can they take on 8 h more? Yes
Let's review the decisions that were made:
task4Hours ?? 0treats the missing estimate as zero hours.||would have worked the same way here, but if the estimate were legitimately0,||would have replaced it with 0 anyway, and in other contexts that would cause trouble.??expresses the intent exactly: "if there is no value, use 0".- The parentheses in
(assignedHours / MAX_WEEKLY_HOURS) * 100are not strictly necessary (/and*have the same precedence and are evaluated left to right), but they make the intent crystal clear. Math.roundstops us from displaying61.25%.- The chained ternary classifies the workload into four bands. It is aligned so that it reads like a table.
canTakeItis a boolean named as a statement of fact; in the output it is turned into text with another ternary.- The
&&short-circuit runs the warning only if the threshold is exceeded. Here it does not run, because61 >= 75is false.
Common Mistakes and Tips
Common mistakes
- Adding text by accident.
'12' + 8gives'128'. Form data always arrives as text; convert it before operating on it. - Forgetting the parentheses in an average.
a + b + c / 3is not the mean. It is the most repeated calculation error in the world. - Using
||for numeric default values.hours || 8turns a legitimate0into8. Use??. - Dividing without checking the divisor.
x / 0silently givesInfinityand contaminates every subsequent calculation. - Mixing
??with||or&&without parentheses. That is aSyntaxError. - Overusing
x++inside expressions.i++ + ++iis a riddle, not code. - Putting
?.everywhere. It silences real bugs. Use it only where the value can legitimately be missing. - Confusing
=with==or===.if (status = 'done')assigns instead of comparing, and always comes out true.
Tips
- Use parentheses whenever there is more than one operator. Clarity is worth more than brevity.
??for default values,||only when you also want to discard0and''.- Template literals for any composed text. It wipes out concatenation mistakes in one stroke.
- The ternary is for choosing a value. If you need to run several statements, use
if. - Name your intermediate results.
const workloadPercentage = ...is infinitely more readable than cramming the whole calculation inside aconsole.log. - Round when displaying, not when calculating. If you round in the middle of a chain of calculations, the error accumulates.
Exercises
Exercise 1: Predict the result
Write down what each line prints and why:
console.log(2 + 3 * 4); // A
console.log('8' + 4); // B
console.log('8' - 4); // C
console.log(10 % 3); // D
console.log(2 ** 3 ** 2); // E
let i = 5;
console.log(i++); // F
console.log(i); // G
console.log(0 || 40); // H
console.log(0 ?? 40); // I
console.log('' ?? 'Unassigned'); // J
console.log(null ?? 'Unassigned'); // K
console.log(!!'done'); // LExercise 2: Round-robin task assignment
The Taller Nómada team has three people in this order: position 0 = Marta, 1 = Iván, 2 = Lucía. Tasks are assigned in turn according to their number.
Write a script that, given a taskNumber, calculates and prints:
- The team position it corresponds to (use
%). - Whether the task number is even or odd.
- A message built with a template literal along the lines of:
Task 7 goes to position 1 (odd number).
Try it with the numbers 5, 6 and 7.
Exercise 3: Lucía's workload report
Write a script that calculates Lucía's weekly workload from this data:
- Weekly maximum: 40 hours.
- Assigned tasks: 10, 6.5 and 3 hours.
- A fourth task whose estimate does not exist yet (it is
null). - She has already spent 12 of the assigned hours.
Calculate and display:
- Total assigned hours (the missing estimate counts as 0, using
??). - Hours still to be spent.
- Progress percentage over the assigned hours, rounded to a whole number.
- Workload percentage over the weekly maximum, rounded.
- Whether she can take on a new 20-hour task (a boolean displayed as "Yes"/"No" with a ternary).
- A warning with
console.warn, using the&&short-circuit, only if the workload is above 40%.
Solutions
Exercise 1
| Line | Result | Explanation |
|---|---|---|
| A | 14 |
* binds tighter than +: 2 + (3*4) |
| B | '84' |
One of the operands is text: + concatenates |
| C | 4 |
- does not concatenate: it converts '8' to a number |
| D | 1 |
The remainder of dividing 10 by 3 |
| E | 512 |
** is right-associative: 2 ** (3**2) = 2**9 |
| F | 5 |
Postfix form: it returns the old value |
| G | 6 |
But the variable has already been incremented |
| H | 40 |
0 is falsy, so || moves on to the second operand |
| I | 0 |
?? only acts on null or undefined |
| J | '' |
The empty string is neither null nor undefined |
| K | 'Unassigned' |
null does trigger ?? |
| L | true |
!! converts to a boolean; a non-empty string is truthy |
Exercise 2
'use strict';
const taskNumber = 7;
// 1. Position on the team (3 people: 0, 1, 2)
const TEAM_SIZE = 3;
const position = taskNumber % TEAM_SIZE;
// 2. Even or odd
const isEven = taskNumber % 2 === 0;
const parity = isEven ? 'even' : 'odd';
// 3. Message
console.log(
`Task ${taskNumber} goes to position ${position} (${parity} number).`
);Results:
taskNumber |
% 3 |
Position | Parity |
|---|---|---|---|
| 5 | 5 % 3 |
2 (Lucía) | odd |
| 6 | 6 % 3 |
0 (Marta) | even |
| 7 | 7 % 3 |
1 (Iván) | odd |
Exercise 3
'use strict';
// --- Data -----------------------------------------------------------
const MAX_WEEKLY_HOURS = 40;
const assignee = 'Lucía';
const task1Hours = 10;
const task2Hours = 6.5;
const task3Hours = 3;
const task4Hours = null; // not estimated yet
const hoursSpent = 12;
// --- Calculations ---------------------------------------------------
const assignedHours =
task1Hours + task2Hours + task3Hours + (task4Hours ?? 0);
const remainingHours = assignedHours - hoursSpent;
const progressPercentage = Math.round((hoursSpent / assignedHours) * 100);
const workloadPercentage = Math.round((assignedHours / MAX_WEEKLY_HOURS) * 100);
const NEW_TASK_HOURS = 20;
const freeHours = MAX_WEEKLY_HOURS - assignedHours;
const canTakeIt = freeHours >= NEW_TASK_HOURS;
// --- Output ---------------------------------------------------------
console.log(`=== Weekly workload for ${assignee} ===`);
console.log(`Assigned: ${assignedHours} h`);
console.log(`Spent: ${hoursSpent} h`);
console.log(`Remaining: ${remainingHours} h`);
console.log(`Progress: ${progressPercentage}%`);
console.log(`Workload: ${workloadPercentage}% of ${MAX_WEEKLY_HOURS} h`);
console.log(
`Can she take on ${NEW_TASK_HOURS} h more? ${canTakeIt ? 'Yes' : 'No'}`
);
workloadPercentage > 40 &&
console.warn(`Warning: ${assignee} is above 40% workload.`);Output:
=== Weekly workload for Lucía === Assigned: 19.5 h Spent: 12 h Remaining: 7.5 h Progress: 62% Workload: 49% of 40 h Can she take on 20 h more? Yes ⚠ Warning: Lucía is above 40% workload.
Points worth highlighting:
task4Hours ?? 0neutralizes the missing value. Without that operator,nullwould end up being converted to0anyway through implicit coercion, but writing it explicitly documents the intent and does not rely on an automatic conversion you may not fully control.- The parentheses in the percentages guarantee that the division happens first and the multiplication by 100 second.
- The
canTakeItcalculation:freeHoursis40 - 19.5 = 20.5, and20.5 >= 20istrue, so the answer is "Yes" by a very tight margin of half an hour. If you had estimated the fourth task at just one hour, the answer would have changed. This is exactly the kind of borderline calculation you want the program to do rather than a person with a calculator.
Conclusion
You now know how to operate on data. You handle the arithmetic operators (+ - * / % **), including modulo for cyclic distribution, and you know about the split personality of +. You can tell the prefix and postfix forms of ++ and -- apart. You use the compound assignment operators (+=, -=, *=...). You understand the logical operators &&, || and !, their short-circuit evaluation and the fact that they return an operand, not a boolean. You know when to use ?? instead of || for default values, and how to apply ??= and ?. to work with data that may be missing. You use the ternary to choose values inside expressions, you prefer template literals to concatenation, and above all you have learned the most profitable lesson of all: when in doubt about precedence, add parentheses.
With all of that you have built the first useful calculation in Nómada Tasks: the weekly workload report for a member of the Taller Nómada team.
But a ghost has appeared several times along the way: '8' + 4 gives '84', null becomes 0 when added, 0 is falsy and so is ''. That is the terrain where people trip up the most. In the next lesson, Type Conversion and Comparisons, you will clear it up completely: implicit and explicit coercion, the exact list of falsy values, and the difference between == and ===. It is the lesson that prevents the majority of beginner errors.
JavaScript Course: From Beginner to Advanced
Module 1: Introduction to JavaScript
- What Is JavaScript?
- Setting Up Your Development Environment
- Your First JavaScript Program
- JavaScript Syntax and Basic Concepts
- Variables and Data Types
- Basic Operators
- Type Conversion and Comparisons
- The Course Project: Nómada Tasks
Module 2: Control Structures
- Conditional Statements
- Loops: for, while, do-while
- Switch Statements
- Flow Control: break, continue and Nested Loops
- Error Handling with try-catch
Module 3: Functions
- Defining and Calling Functions
- Function Expressions and Arrow Functions
- Parameters and Return Values
- Scope and Closures
- Hoisting and the Execution Context
- Higher-Order Functions
- Recursion
Module 4: Objects and Arrays
- Introduction to Objects
- Object Methods and the
thisKeyword - Arrays: Basics and Methods
- Iterating over Arrays
- Searching, Sorting and Aggregating Data: find, sort and reduce
- Array Destructuring
- Object Destructuring, Spread and Rest
- JSON and Copying Objects
Module 5: Advanced Objects and Functions
- Prototypes and Inheritance
- Classes and Object-Oriented Programming
- Encapsulation: Getters, Setters and Private Fields
- Modules: Import and Export
- Asynchronous JavaScript: Callbacks
- Promises and Async/Await
- The Event Loop and the Microtask Queue
- Iterators and Generators
Module 6: The Document Object Model (DOM)
- Introduction to the DOM
- Selecting and Manipulating DOM Elements
- Handling Events
- Propagation, Delegation and Custom Events
- Creating and Removing DOM Elements
- Rendering Lists and HTML Templates
- Handling and Validating Forms
Module 7: Browser APIs and Advanced Topics
- Local and Session Storage
- The Fetch API and AJAX
- Robust Requests: Errors, Timeouts and AbortController
- WebSockets
- Service Workers and Progressive Web Apps (PWAs)
- Essential Browser APIs
- Introduction to WebAssembly
Module 8: Testing and Debugging
- Debugging JavaScript
- Code Quality: ESLint, Prettier and Conventions
- Unit Testing with Jest
- Test Doubles: Mocks, Stubs and Spies
- Integration Testing
- End-to-End Testing with Cypress
Module 9: Performance and Optimization
- Measure Before You Optimize: DevTools and Web Vitals
- Optimizing JavaScript Performance
- Memory Management
- Efficient DOM Manipulation
- Lazy Loading and Code Splitting
Module 10: JavaScript Frameworks and Libraries
- Why Frameworks Exist
- Introduction to React
- State Management with Redux
- Vue.js Basics
- Angular Basics
- Choosing the Right Framework
