javascript
exercises
exercises.js⚡javascript
/**
* ============================================
* 2.3 Type Mechanics - Exercises
* ============================================
*
* Practice type coercion, casting, and comparisons.
* Solutions are at the bottom.
*/
// ============================================
// EXERCISE 1: Coercion Predictions
// ============================================
// Predict the output and type of each expression:
// 1a) "10" + 5 Output: _____ Type: _____
// 1b) "10" - 5 Output: _____ Type: _____
// 1c) "10" * "2" Output: _____ Type: _____
// 1d) 5 + true Output: _____ Type: _____
// 1e) "5" + true Output: _____ Type: _____
// 1f) null + 1 Output: _____ Type: _____
// 1g) undefined + 1 Output: _____ Type: _____
// 1h) "5" - - "3" Output: _____ Type: _____
// ============================================
// EXERCISE 2: String Conversion
// ============================================
// Convert each value to a string using THREE different methods:
let num = 42;
// Method 1 (String function):
// Method 2 (toString method):
// Method 3 (Template literal):
// Method 4 (Concatenation):
// ============================================
// EXERCISE 3: Number Conversion
// ============================================
// Convert each string to a number, note which methods work:
let str1 = '42';
let str2 = '42.5';
let str3 = '42px';
let str4 = 'px42';
// For each string, try:
// - Number()
// - parseInt()
// - parseFloat()
// - Unary +
// YOUR CODE:
// ============================================
// EXERCISE 4: Boolean Conversion
// ============================================
// Convert to boolean and categorize as truthy or falsy:
// Value Boolean() Truthy/Falsy?
// 0 _____ _____
// "0" _____ _____
// "" _____ _____
// "false" _____ _____
// [] _____ _____
// {} _____ _____
// null _____ _____
// undefined _____ _____
// NaN _____ _____
// Infinity _____ _____
// ============================================
// EXERCISE 5: typeof Quiz
// ============================================
// What does typeof return for each?
// typeof 42 → _____
// typeof "42" → _____
// typeof true → _____
// typeof undefined → _____
// typeof null → _____
// typeof Symbol() → _____
// typeof 42n → _____
// typeof [] → _____
// typeof {} → _____
// typeof function(){} → _____
// typeof NaN → _____
// typeof Infinity → _____
// ============================================
// EXERCISE 6: Fix the Type Checking
// ============================================
// This function has bugs. Fix them:
function checkType(value) {
// Bug: doesn't handle null correctly
// Bug: doesn't distinguish arrays from objects
return typeof value;
}
// YOUR FIXED VERSION:
// ============================================
// EXERCISE 7: instanceof Practice
// ============================================
// Create a class hierarchy and test with instanceof:
// Create: Animal > Dog > Labrador
// Then test various instanceof combinations
// YOUR CODE:
// ============================================
// EXERCISE 8: Equality Predictions
// ============================================
// Predict == and === results:
// Expression == ===
// 5 == "5" ___ ___
// 0 == false ___ ___
// 0 === false ___ ___
// null == undefined ___ ___
// null === undefined ___ ___
// NaN == NaN ___ ___
// [] == false ___ ___
// [] === false ___ ___
// "" == 0 ___ ___
// "" == false ___ ___
// ============================================
// EXERCISE 9: Object.is() vs ===
// ============================================
// When do Object.is() and === give different results?
// Object.is(5, 5) _____ 5 === 5 _____
// Object.is(NaN, NaN) _____ NaN === NaN _____
// Object.is(+0, -0) _____ +0 === -0 _____
// Object.is(null, undefined) ___ null === undefined ___
// ============================================
// EXERCISE 10: Create Validation Functions
// ============================================
// Create these validation functions:
// isValidNumber(value) - returns true for real numbers (not NaN, not Infinity)
// isString(value) - returns true for strings (primitive and String objects)
// isEmptyObject(value) - returns true for {} but not for [] or null
// YOUR CODE:
// ============================================
// EXERCISE 11: Coercion Chain
// ============================================
// Trace through this coercion step by step:
// Step through: [] == ![]
// Step 1: Right side - ![] = _____
// Step 2: Now comparing: [] == _____
// Step 3: Coercion happens: _____ == _____
// Step 4: Final result: _____
// ============================================
// EXERCISE 12: Safe Parsing
// ============================================
// Create a function that safely parses user input to number:
// - Returns the number if valid
// - Returns null if invalid
// - Handles edge cases (empty string, whitespace, "Infinity")
function safeParseNumber(input) {
// YOUR CODE:
}
// Test cases:
// safeParseNumber("42") → 42
// safeParseNumber("42.5") → 42.5
// safeParseNumber("42px") → null
// safeParseNumber("") → null
// safeParseNumber(" ") → null
// safeParseNumber("Infinity") → null
// safeParseNumber(null) → null
// ============================================
// EXERCISE 13: Deep Type Check
// ============================================
// Create a function that returns detailed type information:
// getDetailedType(value) should return:
// - "null" for null
// - "array" for arrays
// - "date" for Date objects
// - "regexp" for regular expressions
// - "function" for functions
// - "object" for plain objects
// - The typeof result for primitives
function getDetailedType(value) {
// YOUR CODE:
}
// Tests:
// getDetailedType(null) → "null"
// getDetailedType([1,2,3]) → "array"
// getDetailedType(new Date()) → "date"
// getDetailedType(/regex/) → "regexp"
// getDetailedType(() => {}) → "function"
// getDetailedType({}) → "object"
// getDetailedType(42) → "number"
// getDetailedType("hello") → "string"
// ============================================
// EXERCISE 14: Nullish Coalescing vs OR
// ============================================
// Predict the differences:
// let a = 0;
// a || "default" → _____
// a ?? "default" → _____
// let b = "";
// b || "default" → _____
// b ?? "default" → _____
// let c = null;
// c || "default" → _____
// c ?? "default" → _____
// let d = false;
// d || "default" → _____
// d ?? "default" → _____
// ============================================
// EXERCISE 15: Type-Safe Add Function
// ============================================
// Create a function that adds two values but:
// - Throws error if not both numbers
// - Handles string numbers by converting
// - Returns NaN for invalid conversions
function safeAdd(a, b) {
// YOUR CODE:
}
// Tests:
// safeAdd(5, 3) → 8
// safeAdd("5", "3") → 8
// safeAdd(5, "3") → 8
// safeAdd("hello", 3) → NaN
// safeAdd(null, 3) → Error or NaN?
// ============================================
// ============================================
// SOLUTIONS
// ============================================
// ============================================
/*
// SOLUTION 1: Coercion Predictions
// 1a) "105" Type: string
// 1b) 5 Type: number
// 1c) 20 Type: number
// 1d) 6 Type: number
// 1e) "5true" Type: string
// 1f) 1 Type: number
// 1g) NaN Type: number
// 1h) 8 Type: number
// SOLUTION 2: String Conversion
let num = 42;
String(num); // "42"
num.toString(); // "42"
`${num}`; // "42"
num + ""; // "42"
// SOLUTION 3: Number Conversion
let str1 = "42"; // Number: 42, parseInt: 42, parseFloat: 42, +: 42
let str2 = "42.5"; // Number: 42.5, parseInt: 42, parseFloat: 42.5, +: 42.5
let str3 = "42px"; // Number: NaN, parseInt: 42, parseFloat: 42, +: NaN
let str4 = "px42"; // Number: NaN, parseInt: NaN, parseFloat: NaN, +: NaN
// SOLUTION 4: Boolean Conversion
// 0 false Falsy
// "0" true Truthy
// "" false Falsy
// "false" true Truthy
// [] true Truthy
// {} true Truthy
// null false Falsy
// undefined false Falsy
// NaN false Falsy
// Infinity true Truthy
// SOLUTION 5: typeof Quiz
// typeof 42 → "number"
// typeof "42" → "string"
// typeof true → "boolean"
// typeof undefined → "undefined"
// typeof null → "object" (bug!)
// typeof Symbol() → "symbol"
// typeof 42n → "bigint"
// typeof [] → "object"
// typeof {} → "object"
// typeof function(){} → "function"
// typeof NaN → "number"
// typeof Infinity → "number"
// SOLUTION 6: Fix the Type Checking
function checkType(value) {
if (value === null) return "null";
if (Array.isArray(value)) return "array";
return typeof value;
}
// SOLUTION 7: instanceof Practice
class Animal {}
class Dog extends Animal {}
class Labrador extends Dog {}
const lab = new Labrador();
console.log(lab instanceof Labrador); // true
console.log(lab instanceof Dog); // true
console.log(lab instanceof Animal); // true
console.log(lab instanceof Object); // true
console.log(lab instanceof Array); // false
// SOLUTION 8: Equality Predictions
// 5 == "5" true false
// 0 == false true false
// 0 === false - false
// null == undefined true false
// null === undefined - false
// NaN == NaN false false
// [] == false true false
// [] === false - false
// "" == 0 true false
// "" == false true false
// SOLUTION 9: Object.is() vs ===
// Object.is(5, 5) true 5 === 5 true
// Object.is(NaN, NaN) true NaN === NaN false
// Object.is(+0, -0) false +0 === -0 true
// Object.is(null, undefined) false null === undefined false
// SOLUTION 10: Validation Functions
function isValidNumber(value) {
return typeof value === "number" &&
!Number.isNaN(value) &&
Number.isFinite(value);
}
function isString(value) {
return typeof value === "string" || value instanceof String;
}
function isEmptyObject(value) {
return value !== null &&
typeof value === "object" &&
!Array.isArray(value) &&
Object.keys(value).length === 0;
}
// SOLUTION 11: Coercion Chain
// [] == ![]
// Step 1: ![] = false (! operator converts to boolean, then negates)
// Step 2: [] == false
// Step 3: [] converts to "" then to 0, false converts to 0
// Step 4: 0 == 0 → true
// SOLUTION 12: Safe Parsing
function safeParseNumber(input) {
if (input === null || input === undefined) return null;
if (typeof input === "number") return Number.isFinite(input) ? input : null;
if (typeof input !== "string") return null;
const trimmed = input.trim();
if (trimmed === "" || trimmed === "Infinity" || trimmed === "-Infinity") {
return null;
}
const num = Number(trimmed);
return Number.isFinite(num) ? num : null;
}
// SOLUTION 13: Deep Type Check
function getDetailedType(value) {
if (value === null) return "null";
if (Array.isArray(value)) return "array";
if (value instanceof Date) return "date";
if (value instanceof RegExp) return "regexp";
if (typeof value === "function") return "function";
if (typeof value === "object") return "object";
return typeof value;
}
// SOLUTION 14: Nullish Coalescing vs OR
// let a = 0;
// a || "default" → "default" (0 is falsy)
// a ?? "default" → 0 (0 is not null/undefined)
// let b = "";
// b || "default" → "default" (empty string is falsy)
// b ?? "default" → "" (empty string is not null/undefined)
// let c = null;
// c || "default" → "default"
// c ?? "default" → "default"
// let d = false;
// d || "default" → "default" (false is falsy)
// d ?? "default" → false (false is not null/undefined)
// SOLUTION 15: Type-Safe Add Function
function safeAdd(a, b) {
const numA = typeof a === "number" ? a : Number(a);
const numB = typeof b === "number" ? b : Number(b);
if (Number.isNaN(numA) || Number.isNaN(numB)) {
return NaN;
}
return numA + numB;
}
*/