javascript

exercises

exercises.js
/**
 * ============================================
 * 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;
}

*/
Exercises - JavaScript Tutorial | DeepML