Module 78 : script that checks a user's input grade and prints whether it's an A, B, C, D, or F using both if and switch.
Prerequisites
Basic JavaScript syntax
Functions, conditionals (if, else)
Basic DOM manipulations (for the browser demo) or readline (for Node demo)
API (the functions we'll create)
getLetterGradeIf(score: number): string — returns 'A'|'B'|'C'|'D'|'F' or 'Invalid' on bad input.
getLetterGradeSwitch(score: number): string — same behavior, implemented with switch.
We also provide small wrappers for browser and Node demos.
1) Implementation: if / else if
/**
* Convert numeric score to letter grade using if/else-if.
* Returns 'A', 'B', 'C', 'D', 'F' or 'Invalid'.
*/
function getLetterGradeIf(rawScore) {
// sanitize + validation
const score = Number(rawScore);
if (!Number.isFinite(score)) return 'Invalid';
if (score < 0 || score > 100) return 'Invalid';
// grade logic
if (score >= 90) return 'A';
else if (score >= 80) return 'B';
else if (score >= 70) return 'C';
else if (score >= 60) return 'D';
else return 'F';
}
Notes:
We convert rawScore with Number() to accept string or numeric input (e.g., '85').
Number.isFinite filters out NaN, Infinity, and non-numeric values.
The checks are ordered highest → lowest so a score that meets >= 90 will not be tested against lower ranges.
>= ensures inclusive boundaries (e.g., 90 is an A).
2) Implementation: switch (approach A — map tens to cases)
A common and readable switch pattern for range-based numeric categories is to map the score to its tens integer (Math.floor(score / 10)) and switch on that value:
function getLetterGradeSwitch(rawScore) {
const score = Number(rawScore);
if (!Number.isFinite(score)) return 'Invalid';
if (score < 0 || score > 100) return 'Invalid';
const tens = Math.floor(score / 10); // 100->10, 95->9, 89->8
switch (tens) {
case 10: // fall-through so 100 becomes an A
case 9:
return 'A';
case 8:
return 'B';
case 7:
return 'C';
case 6:
return 'D';
default:
return 'F';
}
}
Notes:
Math.floor(100 / 10) === 10, so we include a case 10 that falls through into case 9.
This switch compares integers (===) so it's fast and clear for discrete buckets.
3) Implementation: switch(true) (approach B — switch on boolean expressions)
Some developers prefer switch(true) so each case tests a boolean expression:
function getLetterGradeSwitchBool(rawScore) {
const score = Number(rawScore);
if (!Number.isFinite(score)) return 'Invalid';
if (score < 0 || score > 100) return 'Invalid';
switch (true) {
case (score >= 90):
return 'A';
case (score >= 80):
return 'B';
case (score >= 70):
return 'C';
case (score >= 60):
return 'D';
default:
return 'F';
}
}
Notes:
switch(true) checks each case expression for truthiness — it's effectively a different syntax for an if chain.
Some teams dislike switch(true) because it's less conventional, but it can be clean when you want to keep a switch-style block.
4) Browser demo (interactive)
<!-- Save as grade-demo.html and open in a browser -->
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Grade Checker Demo</title>
</head>
<body>
<h1>Grade Checker</h1>
<label>Score (0-100): <input id="scoreInput" type="text" /></label>
<select id="method">
<option value="if">If/Else</option>
<option value="switch">Switch (tens)</option>
<option value="switchBool">Switch (boolean)</option>
</select>
<button id="checkBtn">Check Grade</button>
<p id="result"></p>
<script>
// include the functions (getLetterGradeIf, getLetterGradeSwitch, getLetterGradeSwitchBool)
function getLetterGradeIf(rawScore) {
const score = Number(rawScore);
if (!Number.isFinite(score)) return 'Invalid';
if (score < 0 || score > 100) return 'Invalid';
if (score >= 90) return 'A';
else if (score >= 80) return 'B';
else if (score >= 70) return 'C';
else if (score >= 60) return 'D';
else return 'F';
}
function getLetterGradeSwitch(rawScore) {
const score = Number(rawScore);
if (!Number.isFinite(score)) return 'Invalid';
if (score < 0 || score > 100) return 'Invalid';
const tens = Math.floor(score / 10);
switch (tens) {
case 10:
case 9: return 'A';
case 8: return 'B';
case 7: return 'C';
case 6: return 'D';
default: return 'F';
}
5) Node (CLI) demo using readline
// node grade-cli.js
const readline = require('readline');
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
function getLetterGradeIf(rawScore) {
const score = Number(rawScore);
if (!Number.isFinite(score)) return 'Invalid';
if (score < 0 || score > 100) return 'Invalid';
if (score >= 90) return 'A';
else if (score >= 80) return 'B';
else if (score >= 70) return 'C';
else if (score >= 60) return 'D';
else return 'F';
}
rl.question('Enter score (0-100): ', (answer) => {
console.log('Using if/else result:', getLetterGradeIf(answer));
rl.close();
});
6) Tests and example inputs
Input
Expected output
Explanation
95
A
>= 90
90
A
boundary included
89.9
B
< 90 but >=80
80
B
exact boundary
72.5
C
decimals allowed
60
D
boundary
59.999
F
< 60
-5
Invalid
out of range
105
Invalid
out of range
"85"
B
string converts to number
"abc"
Invalid
NaN -> invalid
7) explanation
Sanitization & Validation: Always convert input to a number and check Number.isFinite so you don't process NaN or textual garbage. Reject values outside 0–100 (unless your grading policy allows extra-credit >100).
Why ordered checks matter: In an if chain we check from highest to lowest so that a high score is captured early (if (score >= 90)). If we reversed order we might misclassify.
Switch vs If:
if chains are direct and readable for ordered numeric ranges.
switch is best when you have discrete buckets or want to use fall-through behavior. The Math.floor(score / 10) trick transforms ranges into discrete integers (10, 9, 8, ...), which makes switch elegant.
switch(true) is syntactic sugar for many if conditions; use according to team preference.
Performance: For this use-case the difference is negligible. Clarity and maintainability matter more than micro-optimizations.
Edge cases: Decide how to treat exactly 100 (include in A), negative numbers, not-a-number, and non-integer decimals.
8) Extensions & exercises
Exercise 1 (Beginner)
Modify getLetterGradeIf to return A+, A, A- for the top grade band as follows:
A+ : 97–100
A : 90–96.999...
Hint / Solution sketch: check >= 97 before >= 90.
function getLetterGradeIfPlusMinus(rawScore) {
const score = Number(rawScore);
if (!Number.isFinite(score)) return 'Invalid';
if (score < 0 || score > 100) return 'Invalid';
if (score >= 97) return 'A+';
if (score >= 90) return 'A';
if (score >= 80) return 'B';
// ... and so on
}
Exercise 2 (Intermediate)
Write a function that accepts a custom grade scale object and returns a letter grade.
Example scale:
const scale = [
{ min: 97, grade: 'A+' },
{ min: 90, grade: 'A' },
{ min: 80, grade: 'B' },
// ...
];
Hint: sort scales descending by min, then for (const s of scale) if (score >= s.min) return s.grade;.
Exercise 3 (Testing)
Write unit tests using Jest or simple assertion functions that verify each boundary (59.999, 60, 69.999, 70, etc.).
Exercise 4 (Advanced)
Map a letter grade to a 4.0 GPA value (e.g., A->4.0, B->3.0) and then compute the GPA for an array of course objects [{score, credits}].
Sample solution sketch: compute letter grade, map letter to points, sum weighted points / sum credits.
No comments:
Post a Comment