Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
69c00ce
fix key error in 0.js - duplicate str variable
lamlakamana-oss Sep 26, 2026
01b0572
fix key error in 1.js - duplicate decimalNumber variable and scope issue
lamlakamana-oss Sep 26, 2026
468f39f
Fix 2.js: use a parameter name instead of a number
lamlakamana-oss Sep 28, 2026
d207836
Fix 2-mandatory-debug/0.js: return the product instead of logging it
lamlakamana-oss Sep 28, 2026
8f610f3
Fix 2-mandatory-debug/1.js: put return value on the same line
lamlakamana-oss Sep 28, 2026
69f740e
Fix 2-mandatory-debug/2.js: add num parameter to getLastDigit
lamlakamana-oss Sep 28, 2026
01ee9fd
Implement calculateBMI in 3-mandatory-implement/1-bmi.js
lamlakamana-oss Sep 28, 2026
a37a324
Implement toUpperSnakeCase in 3-mandatory-implement/2-cases.js
lamlakamana-oss Sep 28, 2026
80cb798
Implement toPounds in 3-mandatory-implement/3-to-pounds.js
lamlakamana-oss Sep 28, 2026
a4bab84
Answer questions in 4-mandatory-interpret/time-format.js
lamlakamana-oss Sep 28, 2026
552c37c
Add comprehensive edge case tests for 12-hour clock
lamlakamana-oss Sep 28, 2026
6bc1c9c
Answer question e and rename result variable
lamlakamana-oss Oct 2, 2026
b76934a
Revert "Answer question e and rename result variable"
lamlakamana-oss Oct 2, 2026
5cc752a
Add actual error output and deeper TDZ explanation
lamlakamana-oss Oct 2, 2026
d18dbb8
Fixed shadowing issue and added corrected code
lamlakamana-oss Oct 2, 2026
82cfcc6
Updated BMI calculation to use exponentiation operator
lamlakamana-oss Oct 2, 2026
6736f52
Added blank line for readability
lamlakamana-oss Oct 2, 2026
e2053ed
Removed redundant padEnd on pence calculation
lamlakamana-oss Oct 2, 2026
908f258
Added readability comment, blank line, and fixed header text
lamlakamana-oss Oct 2, 2026
c983ebd
Fixed time logic, added edge case tests, and labeled tests 1 and 2
lamlakamana-oss Oct 2, 2026
87b77ed
Cleaned up ASI explanation
lamlakamana-oss Oct 2, 2026
4634977
Removed reference to specific line number in comment
lamlakamana-oss Oct 2, 2026
297d063
Removed extra parentheses and line number reference
lamlakamana-oss Oct 2, 2026
b2459ed
Added actual error output to comments and restored working code
lamlakamana-oss Oct 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 27 additions & 5 deletions Sprint-3/1-key-errors/0.js
Comment thread
lamlakamana-oss marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -1,13 +1,35 @@
// Predict and explain first...
// =============> write your prediction here
//I think this code will show a SyntaxError. The function has two variables named str in the same scope.
// ACTUAL ERROR (running the original code with `node 0.js`):
// C:\Users\EarthHarvestAdmin\CYF2026 LAMLA KAMANA\Module-JavaScript-Fundamentals\Sprint-3\1-key-errors\0.js:8
let str = `${str[0].toUpperCase()}${str.slice(1)}`;
^

//SyntaxError: Identifier 'str' has already been declared

// WHY IT IS ILLEGAL (DEEPER EXPLANATION):
// 1. SCOPE COLLISION: The function parameter `str` and the variable `let str`
// exist in the exact same function scope. In JavaScript, `let` and `const`
// do NOT allow redeclaring an existing variable in the same scope.
//
// 2. TEMPORAL DEAD ZONE (TDZ): When the JavaScript engine parses this function,
// it hoists the `let str` declaration to the top of the function scope.
// However, unlike `var`, `let` variables remain in an uninitialized state
// (the TDZ) until the exact line of declaration is executed.
//
// 3. FATAL PARSING ERROR: Because this is a SyntaxError (not a runtime error),
// the JavaScript engine catches the illegal redeclaration during the
// compilation/parsing phase, BEFORE any code executes. This is why the
// `console.log` on line 12 never runs—the script never gets past the
// parsing stage.
//
// FIX: use a different name for the new variable, e.g. `result`.
// call the function capitalise with a string input
// interpret the error message and figure out why an error is occurring

function capitalise(str) {
let str = `${str[0].toUpperCase()}${str.slice(1)}`;
let str = `${str[0].toUpperCase()}${str.slice(1)}`;
return str;
}

// =============> write your explanation here
// =============> write your new code here
console.log(capitalise("hello"));
// str is used both as the function parameter (function capitalise(str)) and again in let str = ...
22 changes: 13 additions & 9 deletions Sprint-3/1-key-errors/1.js
Comment thread
lamlakamana-oss marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
// Predict and explain first...

// Why will an error occur when this program runs?
// =============> write your prediction here
// I predict this will cause a SyntaxError first (at parse time) because
// decimalNumber is declared twice in the same scope.

// Try playing computer with the example to work out what is going on
// Once the SyntaxError is fixed, a ReferenceError will appear at runtime.
// This is because we would need to rename one of the variables so the
// function can actually use it.

function convertToPercentage(decimalNumber) {
const decimalNumber = 0.5;
const percentage = `${decimalNumber * 100}%`;

const percentage = `${decimalNumber * 100}%`;
return percentage;
}

console.log(decimalNumber);
console.log(convertToPercentage(0.5));

// =============> write your explanation here
// decimalNumber is declared twice in the same scope, once as the function's parameter, and again with const inside the function body. JavaScript doesn't allow redeclaring the same name in the same scope. Even after fixing that, console.log(decimalNumber) would fail too, because decimalNumber only exists inside the function.
//ACTUAL ERROR (SyntaxError):.
// C:\Users\EarthHarvestAdmin\CYF2026 LAMLA KAMANA\Module-JavaScript-Fundamentals\Sprint-3\1-key-errors\1.js:12
// const decimalNumber = `$ {decimalNumber * 100}%`;
// ^

// Finally, correct the code to fix the problem
// =============> write your new code here
// SyntaxError: Identifier 'decimalNumber' has already been declared
11 changes: 9 additions & 2 deletions Sprint-3/1-key-errors/2.js
Comment thread
lamlakamana-oss marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,24 @@
// this function should square any number but instead we're going to get an error

// =============> write your prediction of the error here
// I predict a SyntaxError, because 3 is a number, not a parameter name.
// Function parameters must be identifiers (variable names).

function square(3) {
function square(num) {
return num * num;
}

// =============> write the error message here
// SyntaxError: Unexpected number

// =============> explain this error message here
// The original code was function square(3) { ... }. A function definition
// expects a parameter name inside the brackets, but I gave it the value 3.
// JavaScript found a number where it expected a name, so it says
// "Unexpected number".

// Finally, correct the code to fix the problem

// =============> write your new code here

console.log(square(3));

11 changes: 10 additions & 1 deletion Sprint-3/2-mandatory-debug/0.js
Comment thread
lamlakamana-oss marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
// Predict and explain first...

// =============> write your prediction here
// I predict it will print 320 first (from the console.log inside multiply),
// and then "The result of multiplying 10 and 32 is undefined", because
// multiply does not return a value.

function multiply(a, b) {
console.log(a * b);
return a * b;
}

console.log(`The result of multiplying 10 and 32 is ${multiply(10, 32)}`);

// =============> write your explanation here
// multiply only logs a * b to the console. It has no return statement, so
// multiply(10, 32) evaluates to undefined. The template string in the console.log
// puts that undefined into the sentence. The 320 appears on its own line
// because console.log runs inside the function.

// Finally, correct the code to fix the problem
// =============> write your new code here
// I changed console.log(a * b) to return a * b inside multiply, so the
// function hands the result back to the caller instead of only printing it.
10 changes: 8 additions & 2 deletions Sprint-3/2-mandatory-debug/1.js
Comment thread
lamlakamana-oss marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
// Predict and explain first...
// =============> write your prediction here
// I predict it will print "The sum of 10 and 32 is undefined", because
// the function returns before it reaches a + b.

function sum(a, b) {
return;
a + b;
return a + b;
}

console.log(`The sum of 10 and 32 is ${sum(10, 32)}`);

// =============> write your explanation here
// The return statement was on its own line with nothing after it, so the
// function returned undefined straight away. This is caused by automatic
// semicolon insertion (ASI), where JavaScript treats the line break after
// 'return' as the end of the statement, so 'a + b' was never reached.
// Finally, correct the code to fix the problem
// =============> write your new code here
// I moved a + b onto the same line as return: return a + b
19 changes: 16 additions & 3 deletions Sprint-3/2-mandatory-debug/2.js
Comment thread
lamlakamana-oss marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

// Predict the output of the following code:
// =============> Write your prediction here
// I predict every line will say the last digit is 3, because the function
// ignores the number I pass in and always uses num = 103.

const num = 103;

function getLastDigit() {

function getLastDigit(num) {
return num.toString().slice(-1);
}

Expand All @@ -15,10 +17,21 @@ console.log(`The last digit of 806 is ${getLastDigit(806)}`);

// Now run the code and compare the output to your prediction
// =============> write the output here
// The last digit of 42 is 3
// The last digit of 105 is 3
// The last digit of 806 is 3
// Explain why the output is the way it is
// =============> write your explanation here
// This is called shadowing. Originally, getLastDigit had no parameter, so
// the argument (e.g., 42) was ignored. Inside the function, 'num' referred to
// the global constant 'num = 103', which is why it always returned "3".
// Finally, correct the code to fix the problem
// =============> write your new code here

// I added num as a parameter: function getLastDigit(num). Now num is the
// value I pass in, not the global num = 103.
// This program should tell the user the last digit of each number.
// Explain why getLastDigit is not working properly - correct the problem

console.log(getLastDigit(42));
console.log(getLastDigit(105));
console.log(getLastDigit(806));
13 changes: 3 additions & 10 deletions Sprint-3/3-mandatory-implement/1-bmi.js
Comment thread
lamlakamana-oss marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,9 @@

// For example, if you weigh 70kg (around 11 stone) and are 1.73m (around 5 feet 8 inches) tall, you work out your BMI by:

// squaring your height: 1.73 x 1.73 = 2.99
// dividing 70 by 2.99 = 23.41
// Your result will be displayed to 1 decimal place, for example '23.4'.

// You will need to implement a function that calculates the BMI of someone based off their weight and height

// Given someone's weight in kg and height in metres
// Then when we call this function with the weight and height
// It should return a string of their Body Mass Index to 1 decimal place

function calculateBMI(weight, height) {
// return the BMI of someone based off their weight and height
const bmi = weight / (height ** 2);
return bmi.toFixed(1);
}
console.log(calculateBMI(70, 1.73));
7 changes: 7 additions & 0 deletions Sprint-3/3-mandatory-implement/2-cases.js
Comment thread
lamlakamana-oss marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,10 @@
// You will need to come up with an appropriate name for the function
// Use the MDN string documentation to help you find a solution
// This might help https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase

function toUpperSnakeCase(str) {
return str.toUpperCase().replaceAll(" ", "_");
}

console.log(toUpperSnakeCase("hello there"));
console.log(toUpperSnakeCase("lord of the rings"));
23 changes: 23 additions & 0 deletions Sprint-3/3-mandatory-implement/3-to-pounds.js
Comment thread
lamlakamana-oss marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,26 @@
// You will need to declare a function called toPounds with an appropriately named parameter.

// You should call this function a number of times to check it works for different inputs

function toPounds(penceString) {
const penceStringWithoutTrailingP = penceString.substring(
0,
penceString.length - 1
);
// padStart ensures at least 3 digits (e.g., "5" becomes "005")
const paddedPenceNumberString = penceStringWithoutTrailingP.padStart(3, "0");
const pounds = paddedPenceNumberString.substring(
0,
paddedPenceNumberString.length - 2
);

const pence = paddedPenceNumberString
.substring(paddedPenceNumberString.length - 2);

return `£${pounds}.${pence}`;
}

console.log(toPounds("399p"));
console.log(toPounds("5p"));
console.log(toPounds("45p"));
console.log(toPounds("1250p"));
8 changes: 8 additions & 0 deletions Sprint-3/4-mandatory-interpret/time-format.js
Comment thread
lamlakamana-oss marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,25 @@ function formatTimeDisplay(seconds) {

// a) When formatTimeDisplay is called how many times will pad be called?
// =============> write your answer here
// 3 times. The return line calls pad once each for hours, minutes and seconds.

// Call formatTimeDisplay with an input of 61, now answer the following:

// b) What is the value assigned to num when pad is called for the first time?
// =============> write your answer here
// 0. The first call is pad(totalHours), and totalHours is 0 for an input of 61.

// c) What is the return value of pad when it is called for the first time?
// =============> write your answer here
// "00". num.toString() gives "0", which is shorter than 2 characters, so the
// while loop adds one "0" to the front. pad always returns a string.

// d) What is the value assigned to num when pad is called for the last time in this program? Explain your answer
// =============> write your answer here
// 1. The last call is pad(remainingSeconds), and remainingSeconds is 61 % 60 = 1.

// e) What is the return value of pad when it is called for the last time in this program? Explain your answer
// =============> write your answer here
// "01". num.toString() gives "1", which is too short, so the loop adds a "0"
// to the front.
console.log(formatTimeDisplay(61));
83 changes: 77 additions & 6 deletions Sprint-3/5-stretch-extend/format-time.js
Comment thread
lamlakamana-oss marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,94 @@
// Your task is to write tests for as many different groups of input data or edge cases as you can, and fix any bugs you find.

function formatAs12HourClock(time) {
const hours = Number(time.slice(0, 2));
if (hours > 12) {
return `${hours - 12}:00 pm`;
// Split "08:00" into hours "08" and minutes "00"
const [hourString, minutes] = time.split(":");
let hours = Number(hourString);

// Determine if it is AM or PM
const period = hours >= 12 ? "pm" : "am";

// Convert 24-hour format to 12-hour format
if (hours === 0) {
hours = 12; // Midnight (00:xx) becomes 12:xx am
} else if (hours > 12) {
hours = hours - 12; // Afternoon/evening (13:xx - 23:xx) becomes 1:xx - 11:xx pm
}
return `${time} am`;
}

// Pad the hours with a leading zero if needed (e.g., "8" becomes "08")
const paddedHours = hours.toString().padStart(2, "0");

return `${paddedHours}:${minutes} ${period}`;
}
// Test 1: Morning time
const currentOutput = formatAs12HourClock("08:00");
const targetOutput = "08:00 am";
console.assert(
currentOutput === targetOutput,
`current output: ${currentOutput}, target output: ${targetOutput}`
);

// Test 2: Evening time
const currentOutput2 = formatAs12HourClock("23:00");
const targetOutput2 = "11:00 pm";
console.assert(
currentOutput2 === targetOutput2,
`current output: ${currentOutput2}, target output: ${targetOutput2}`
);
// Test 3: Edge case for 12:00 (Noon)
// The current function logic thinks 12 > 12 is false, so it returns "12:00 am".
// This is technically a bug in the provided function, but a good test case!
const currentOutput3 = formatAs12HourClock("12:00");
const targetOutput3 = "12:00 pm"; // Correct expectation
console.assert(
currentOutput3 === targetOutput3,
`Noon Test Failed -> current output: ${currentOutput3}, target output: ${targetOutput3}`
);

// Test 4: Check for formatting bug (dropping minutes)
// The current function returns `${hours - 12}:00 pm` which ignores the minutes.
const currentOutput4 = formatAs12HourClock("13:45");
const targetOutput4 = "01:45 pm";
console.assert(
currentOutput4 === targetOutput4,
`Minute Formatting Failed -> current output: ${currentOutput4}, target output: ${targetOutput4}`
);

// Test 5: Test single digit hour formatting
// Usually, 12-hour clocks are written as "01:00 pm", not "1:00 pm"
const currentOutput5 = formatAs12HourClock("13:00");
const targetOutput5 = "01:00 pm";
console.assert(
currentOutput5 === targetOutput5,
`Hour Padding Failed -> current output: ${currentOutput5}, target output: ${targetOutput5}`
);

// Test 6: Midnight check
const currentOutput6 = formatAs12HourClock("00:00");
const targetOutput6 = "12:00 am";
console.assert(
currentOutput6 === targetOutput6,
`Midnight Test Failed -> current output: ${currentOutput6}, target output: ${targetOutput6}`
);
// Test 7: Noon edge case (12:30)
const currentOutput7 = formatAs12HourClock("12:30");
const targetOutput7 = "12:30 pm";
console.assert(
currentOutput7 === targetOutput7,
`Noon Test Failed -> current: ${currentOutput7}, target: ${targetOutput7}`
);

// Test 8: Midnight edge case (00:30)
const currentOutput8 = formatAs12HourClock("00:30");
const targetOutput8 = "12:30 am";
console.assert(
currentOutput8 === targetOutput8,
`Midnight Test Failed -> current: ${currentOutput8}, target: ${targetOutput8}`
);

// Test 9: Last minute of the day (23:59)
const currentOutput9 = formatAs12HourClock("23:59");
const targetOutput9 = "11:59 pm";
console.assert(
currentOutput9 === targetOutput9,
`Late Night Test Failed -> current: ${currentOutput9}, target: ${targetOutput9}`
);