javascript

exercises

exercises.js
/**
 * ============================================
 * 3.3 Logical Operators - Exercises
 * ============================================
 *
 * Practice logical operations in JavaScript.
 * Solutions are at the bottom.
 */

// ============================================
// EXERCISE 1: Predict AND Results
// ============================================
// Without running, predict the output:

// true && true        → _____
// true && false       → _____
// 5 && 10             → _____
// 0 && 10             → _____
// "hello" && "world"  → _____
// null && "hello"     → _____
// "" && "hello"       → _____
// 1 && 2 && 3 && 4    → _____
// 1 && 0 && 3 && 4    → _____

// ============================================
// EXERCISE 2: Predict OR Results
// ============================================
// Without running, predict the output:

// true || false       → _____
// false || true       → _____
// 0 || 10             → _____
// 5 || 10             → _____
// "" || "default"     → _____
// null || undefined || "fallback" → _____
// "first" || "second" → _____
// 0 || "" || null || "last" → _____

// ============================================
// EXERCISE 3: NOT and Double NOT
// ============================================
// Predict the boolean result:

// !true               → _____
// !0                  → _____
// !""                 → _____
// ![]                 → _____
// !{}                 → _____
// !!"hello"           → _____
// !!0                 → _____
// !![]                → _____
// !!null              → _____

// ============================================
// EXERCISE 4: Short-Circuit Execution
// ============================================
// Which log statements will execute?

// true && console.log("A");
// false && console.log("B");
// true || console.log("C");
// false || console.log("D");
// null && console.log("E");
// 1 && 2 && console.log("F");
// 0 || "" || console.log("G");

// Answers:
// A: ___ B: ___ C: ___ D: ___ E: ___ F: ___ G: ___

// ============================================
// EXERCISE 5: Default Values
// ============================================
// Create a function that provides default values for missing properties

function createUser(options) {
  // Use logical operators to provide defaults:
  // - name: default "Anonymous"
  // - age: default 0 (⚠️ be careful, 0 is a valid age!)
  // - active: default true (⚠️ false is valid!)
  // YOUR CODE:
}

// Tests:
// createUser({})                    → { name: "Anonymous", age: 0, active: true }
// createUser({ name: "John" })      → { name: "John", age: 0, active: true }
// createUser({ age: 25 })           → { name: "Anonymous", age: 25, active: true }
// createUser({ active: false })     → { name: "Anonymous", age: 0, active: false }
// createUser({ age: 0 })            → { name: "Anonymous", age: 0, active: true }

// ============================================
// EXERCISE 6: || vs ??
// ============================================
// Predict the differences:

// 0 || 10             → _____
// 0 ?? 10             → _____
// "" || "default"     → _____
// "" ?? "default"     → _____
// false || true       → _____
// false ?? true       → _____
// null || "backup"    → _____
// null ?? "backup"    → _____
// undefined || "x"    → _____
// undefined ?? "x"    → _____

// ============================================
// EXERCISE 7: Logical Assignment
// ============================================
// What is the final value of each variable?

let a = 5;
a &&= 10;
// a = _____

let b = 0;
b &&= 10;
// b = _____

let c = 0;
c ||= 10;
// c = _____

let d = 5;
d ||= 10;
// d = _____

let e = null;
e ??= 'default';
// e = _____

let f = 0;
f ??= 10;
// f = _____

// ============================================
// EXERCISE 8: Permission System
// ============================================
// Create a function to check if a user can perform an action

function canPerformAction(user, action) {
  // Rules:
  // - If user is null/undefined, return false
  // - Admins can perform any action
  // - Moderators can perform "edit" and "delete" but not "admin"
  // - Regular users can only perform "edit"
  // - Action must be one of: "edit", "delete", "admin"
  // YOUR CODE:
}

// Tests:
// canPerformAction(null, "edit")                       → false
// canPerformAction({ role: "admin" }, "admin")         → true
// canPerformAction({ role: "moderator" }, "delete")    → true
// canPerformAction({ role: "moderator" }, "admin")     → false
// canPerformAction({ role: "user" }, "edit")           → true
// canPerformAction({ role: "user" }, "delete")         → false

// ============================================
// EXERCISE 9: Validation Chain
// ============================================
// Create a validation function using logical operators

function validateForm(data) {
  // Validate:
  // - name: required, must be non-empty string
  // - email: required, must contain @
  // - age: optional, but if provided must be positive number
  // Return { valid: boolean, error: string | null }
  // YOUR CODE:
}

// Tests:
// validateForm({ name: "John", email: "john@test.com" })
//   → { valid: true, error: null }
// validateForm({ name: "", email: "john@test.com" })
//   → { valid: false, error: "Name is required" }
// validateForm({ name: "John", email: "invalid" })
//   → { valid: false, error: "Invalid email" }
// validateForm({ name: "John", email: "j@t.com", age: -5 })
//   → { valid: false, error: "Age must be positive" }

// ============================================
// EXERCISE 10: Safe Property Access
// ============================================
// Create a function to safely access nested properties

function safeGet(obj, path) {
  // path is a string like "user.address.city"
  // Return the value or undefined if any part is missing
  // YOUR CODE:
}

// Tests:
// let data = { user: { address: { city: "NYC" } } };
// safeGet(data, "user.address.city")    → "NYC"
// safeGet(data, "user.address.zip")     → undefined
// safeGet(data, "user.phone.number")    → undefined
// safeGet(null, "user")                 → undefined

// ============================================
// EXERCISE 11: All/Any Functions
// ============================================
// Create functions that check arrays

function all(arr, predicate) {
  // Return true if predicate returns true for ALL elements
  // Return true for empty array
  // YOUR CODE:
}

function any(arr, predicate) {
  // Return true if predicate returns true for ANY element
  // Return false for empty array
  // YOUR CODE:
}

// Tests:
// all([2, 4, 6], n => n % 2 === 0)      → true
// all([2, 3, 6], n => n % 2 === 0)      → false
// all([], n => n > 0)                   → true
// any([1, 2, 3], n => n > 2)            → true
// any([1, 2, 3], n => n > 5)            → false
// any([], n => n > 0)                   → false

// ============================================
// EXERCISE 12: Operator Precedence
// ============================================
// Predict the results (no parentheses added):

// !true || false && true    → _____
// true || false && false    → _____
// true && false || true     → _____
// !false && !false          → _____
// false || true && false || true → _____

// ============================================
// EXERCISE 13: Conditional Configuration
// ============================================
// Create a function that builds a configuration object

function buildConfig(env, overrides) {
  // env is "development" or "production"
  // overrides is an optional object with any settings to override
  // Return merged config
  // Development defaults: { debug: true, logLevel: "verbose", minify: false }
  // Production defaults: { debug: false, logLevel: "error", minify: true }
  // YOUR CODE:
}

// Tests:
// buildConfig("development")
//   → { debug: true, logLevel: "verbose", minify: false }
// buildConfig("production")
//   → { debug: false, logLevel: "error", minify: true }
// buildConfig("production", { debug: true })
//   → { debug: true, logLevel: "error", minify: true }

// ============================================
// EXERCISE 14: Toggle with Conditions
// ============================================
// Create a function that toggles a feature with conditions

function toggleFeature(features, featureName, conditions) {
  // Toggle the feature only if all conditions are met
  // conditions is an object like { userRole: "admin", isEnabled: true }
  // Return new features object
  // YOUR CODE:
}

// Tests:
// let features = { darkMode: false };
// toggleFeature(features, "darkMode", { enabled: true })
//   → { darkMode: true }
// toggleFeature(features, "darkMode", { enabled: false })
//   → { darkMode: false } (not toggled)

// ============================================
// EXERCISE 15: Expression Equivalence
// ============================================
// Rewrite using only && and || (no if statements):

// Original:
function original(a, b, c) {
  if (a) {
    if (b) {
      return c;
    } else {
      return b;
    }
  } else {
    return a;
  }
}

// Rewrite with only logical operators:
function rewritten(a, b, c) {
  // YOUR CODE:
}

// Both should return the same results for:
// (true, true, "c")   → "c"
// (true, false, "c")  → false
// (false, true, "c")  → false

// ============================================
// ============================================
//              SOLUTIONS
// ============================================
// ============================================

/*

// SOLUTION 1: Predict AND Results
// true && true        → true
// true && false       → false
// 5 && 10             → 10
// 0 && 10             → 0
// "hello" && "world"  → "world"
// null && "hello"     → null
// "" && "hello"       → ""
// 1 && 2 && 3 && 4    → 4
// 1 && 0 && 3 && 4    → 0


// SOLUTION 2: Predict OR Results
// true || false       → true
// false || true       → true
// 0 || 10             → 10
// 5 || 10             → 5
// "" || "default"     → "default"
// null || undefined || "fallback" → "fallback"
// "first" || "second" → "first"
// 0 || "" || null || "last" → "last"


// SOLUTION 3: NOT and Double NOT
// !true               → false
// !0                  → true
// !""                 → true
// ![]                 → false (arrays are truthy!)
// !{}                 → false (objects are truthy!)
// !!"hello"           → true
// !!0                 → false
// !![]                → true
// !!null              → false


// SOLUTION 4: Short-Circuit Execution
// A: executes, B: skipped, C: skipped, D: executes,
// E: skipped, F: executes, G: executes


// SOLUTION 5: Default Values
function createUser(options) {
    return {
        name: options?.name || "Anonymous",
        age: options?.age ?? 0,        // Use ?? to allow 0
        active: options?.active ?? true // Use ?? to allow false
    };
}


// SOLUTION 6: || vs ??
// 0 || 10             → 10
// 0 ?? 10             → 0
// "" || "default"     → "default"
// "" ?? "default"     → ""
// false || true       → true
// false ?? true       → false
// null || "backup"    → "backup"
// null ?? "backup"    → "backup"
// undefined || "x"    → "x"
// undefined ?? "x"    → "x"


// SOLUTION 7: Logical Assignment
// a = 10 (5 is truthy, so assign 10)
// b = 0 (0 is falsy, so don't assign)
// c = 10 (0 is falsy, so assign 10)
// d = 5 (5 is truthy, so don't assign)
// e = "default" (null, so assign)
// f = 0 (0 is not nullish, so don't assign)


// SOLUTION 8: Permission System
function canPerformAction(user, action) {
    if (!user) return false;
    
    const validActions = ["edit", "delete", "admin"];
    if (!validActions.includes(action)) return false;
    
    if (user.role === "admin") return true;
    if (user.role === "moderator") return action !== "admin";
    if (user.role === "user") return action === "edit";
    
    return false;
}


// SOLUTION 9: Validation Chain
function validateForm(data) {
    if (!data?.name || data.name.trim() === "") {
        return { valid: false, error: "Name is required" };
    }
    
    if (!data?.email || !data.email.includes("@")) {
        return { valid: false, error: "Invalid email" };
    }
    
    if (data.age !== undefined && (typeof data.age !== "number" || data.age < 0)) {
        return { valid: false, error: "Age must be positive" };
    }
    
    return { valid: true, error: null };
}


// SOLUTION 10: Safe Property Access
function safeGet(obj, path) {
    if (!obj) return undefined;
    
    const keys = path.split(".");
    let current = obj;
    
    for (const key of keys) {
        if (current === null || current === undefined) {
            return undefined;
        }
        current = current[key];
    }
    
    return current;
}


// SOLUTION 11: All/Any Functions
function all(arr, predicate) {
    for (let item of arr) {
        if (!predicate(item)) return false;
    }
    return true;
}

function any(arr, predicate) {
    for (let item of arr) {
        if (predicate(item)) return true;
    }
    return false;
}


// SOLUTION 12: Operator Precedence
// !true || false && true    → false (false || false)
// true || false && false    → true (true || false)
// true && false || true     → true (false || true)
// !false && !false          → true (true && true)
// false || true && false || true → true


// SOLUTION 13: Conditional Configuration
function buildConfig(env, overrides = {}) {
    const defaults = env === "production" 
        ? { debug: false, logLevel: "error", minify: true }
        : { debug: true, logLevel: "verbose", minify: false };
    
    return {
        debug: overrides.debug ?? defaults.debug,
        logLevel: overrides.logLevel ?? defaults.logLevel,
        minify: overrides.minify ?? defaults.minify
    };
}


// SOLUTION 14: Toggle with Conditions
function toggleFeature(features, featureName, conditions) {
    const allConditionsMet = Object.values(conditions).every(v => !!v);
    
    if (allConditionsMet) {
        return { ...features, [featureName]: !features[featureName] };
    }
    
    return { ...features };
}


// SOLUTION 15: Expression Equivalence
function rewritten(a, b, c) {
    return a && (b && c || !b && b) || !a && a;
}
// Or simpler:
function rewritten(a, b, c) {
    return a ? (b ? c : b) : a;
}

*/
Exercises - JavaScript Tutorial | DeepML