diff --git a/Sprint-3/1-key-errors/0.js b/Sprint-3/1-key-errors/0.js index 653d6f5a0..a0052f79f 100644 --- a/Sprint-3/1-key-errors/0.js +++ b/Sprint-3/1-key-errors/0.js @@ -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 = ... diff --git a/Sprint-3/1-key-errors/1.js b/Sprint-3/1-key-errors/1.js index f2d56151f..a9b68445f 100644 --- a/Sprint-3/1-key-errors/1.js +++ b/Sprint-3/1-key-errors/1.js @@ -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 \ No newline at end of file diff --git a/Sprint-3/1-key-errors/2.js b/Sprint-3/1-key-errors/2.js index aad57f7cf..a29639d12 100644 --- a/Sprint-3/1-key-errors/2.js +++ b/Sprint-3/1-key-errors/2.js @@ -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)); diff --git a/Sprint-3/2-mandatory-debug/0.js b/Sprint-3/2-mandatory-debug/0.js index b27511b41..e3e9acf7f 100644 --- a/Sprint-3/2-mandatory-debug/0.js +++ b/Sprint-3/2-mandatory-debug/0.js @@ -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. \ No newline at end of file diff --git a/Sprint-3/2-mandatory-debug/1.js b/Sprint-3/2-mandatory-debug/1.js index 37cedfbcf..d7ce9750d 100644 --- a/Sprint-3/2-mandatory-debug/1.js +++ b/Sprint-3/2-mandatory-debug/1.js @@ -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 diff --git a/Sprint-3/2-mandatory-debug/2.js b/Sprint-3/2-mandatory-debug/2.js index 57d3f5dc3..68fe9b924 100644 --- a/Sprint-3/2-mandatory-debug/2.js +++ b/Sprint-3/2-mandatory-debug/2.js @@ -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); } @@ -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)); \ No newline at end of file diff --git a/Sprint-3/3-mandatory-implement/1-bmi.js b/Sprint-3/3-mandatory-implement/1-bmi.js index 58b1085f1..c81d7face 100644 --- a/Sprint-3/3-mandatory-implement/1-bmi.js +++ b/Sprint-3/3-mandatory-implement/1-bmi.js @@ -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)); diff --git a/Sprint-3/3-mandatory-implement/2-cases.js b/Sprint-3/3-mandatory-implement/2-cases.js index 5b0ef77ad..29f14102e 100644 --- a/Sprint-3/3-mandatory-implement/2-cases.js +++ b/Sprint-3/3-mandatory-implement/2-cases.js @@ -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")); \ No newline at end of file diff --git a/Sprint-3/3-mandatory-implement/3-to-pounds.js b/Sprint-3/3-mandatory-implement/3-to-pounds.js index 10754da73..02c02a0cf 100644 --- a/Sprint-3/3-mandatory-implement/3-to-pounds.js +++ b/Sprint-3/3-mandatory-implement/3-to-pounds.js @@ -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")); \ No newline at end of file diff --git a/Sprint-3/4-mandatory-interpret/time-format.js b/Sprint-3/4-mandatory-interpret/time-format.js index c0dd9c9a5..86fccdf72 100644 --- a/Sprint-3/4-mandatory-interpret/time-format.js +++ b/Sprint-3/4-mandatory-interpret/time-format.js @@ -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)); \ No newline at end of file diff --git a/Sprint-3/5-stretch-extend/format-time.js b/Sprint-3/5-stretch-extend/format-time.js index 32a32e66b..c753c48af 100644 --- a/Sprint-3/5-stretch-extend/format-time.js +++ b/Sprint-3/5-stretch-extend/format-time.js @@ -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}` +); \ No newline at end of file