javascript

exercises

exercises.js
/**
 * ============================================
 * 3.4 Assignment Operators - Exercises
 * ============================================
 *
 * Practice assignment operations in JavaScript.
 * Solutions are at the bottom.
 */

// ============================================
// EXERCISE 1: Compound Assignment
// ============================================
// Calculate final values without running code:

let a = 10;
a += 5; // a = _____
a *= 2; // a = _____
a -= 10; // a = _____
a /= 4; // a = _____
a %= 3; // a = _____

// ============================================
// EXERCISE 2: String Building
// ============================================
// Use += to build this string: "Hello, World! How are you?"

let greeting = '';
// YOUR CODE (use multiple += operations):

// ============================================
// EXERCISE 3: Logical Assignment Predictions
// ============================================
// Predict the final values:

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

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

let b3 = '';
b3 ||= 'default'; // b3 = _____

let b4 = 'hello';
b4 ||= 'default'; // b4 = _____

let b5 = null;
b5 ??= 'fallback'; // b5 = _____

let b6 = 0;
b6 ??= 100; // b6 = _____

// ============================================
// EXERCISE 4: Array Destructuring
// ============================================
// Extract values from this array:

const colors = ['red', 'green', 'blue', 'yellow', 'purple'];

// Extract first color into 'primary'
// Extract second and third into 'secondary1' and 'secondary2'
// Extract remaining into 'others'

// YOUR CODE:

// ============================================
// EXERCISE 5: Object Destructuring
// ============================================
// Extract from this object:

const person = {
  name: 'Alice',
  age: 28,
  address: {
    city: 'Boston',
    zip: '02101',
  },
  hobbies: ['reading', 'hiking'],
};

// Extract name (rename to personName)
// Extract age with default of 0
// Extract city from nested address
// Extract hobbies

// YOUR CODE:

// ============================================
// EXERCISE 6: Swap Variables
// ============================================
// Swap the values of x and y using destructuring (no temp variable)

let x = 100;
let y = 200;

// YOUR CODE:

// After: x should be 200, y should be 100

// ============================================
// EXERCISE 7: Function with Destructured Parameters
// ============================================
// Create a function that accepts config object with defaults

function createServer(/* YOUR PARAMETERS */) {
  // Default port: 3000
  // Default host: "localhost"
  // Default secure: false
  // Return formatted string: "http://localhost:3000" or "https://..."
  // YOUR CODE:
}

// Tests:
// createServer({})                        → "http://localhost:3000"
// createServer({ port: 8080 })            → "http://localhost:8080"
// createServer({ host: "example.com", secure: true }) → "https://example.com:3000"

// ============================================
// EXERCISE 8: Counter Class
// ============================================
// Create a counter using compound assignment

function createCounter(initial = 0) {
  // Return object with:
  // - value: current count
  // - increment(n = 1): add n to count
  // - decrement(n = 1): subtract n from count
  // - reset(): reset to initial value
  // - double(): multiply count by 2
  // YOUR CODE:
}

// Tests:
// const c = createCounter(10);
// c.increment();    // value: 11
// c.increment(5);   // value: 16
// c.double();       // value: 32
// c.decrement(2);   // value: 30
// c.reset();        // value: 10

// ============================================
// EXERCISE 9: Config Merger
// ============================================
// Create a function that merges configs using ??=

function mergeWithDefaults(config) {
  // Defaults:
  // - timeout: 5000
  // - retries: 3
  // - debug: false
  // - maxConnections: 10
  // Use ??= to set defaults without overwriting valid falsy values
  // YOUR CODE:
}

// Tests:
// mergeWithDefaults({})
//   → { timeout: 5000, retries: 3, debug: false, maxConnections: 10 }
// mergeWithDefaults({ timeout: 1000, retries: 0 })
//   → { timeout: 1000, retries: 0, debug: false, maxConnections: 10 }
// mergeWithDefaults({ debug: true })
//   → { timeout: 5000, retries: 3, debug: true, maxConnections: 10 }

// ============================================
// EXERCISE 10: Multiple Return Values
// ============================================
// Create a function that returns statistics about an array
// Use destructuring to extract the results

function getStats(numbers) {
  // Return object with: min, max, sum, average, count
  // YOUR CODE:
}

// Usage:
// const { min, max, average } = getStats([1, 2, 3, 4, 5]);

// ============================================
// EXERCISE 11: Deep Destructuring
// ============================================
// Extract deeply nested values

const data = {
  users: [
    { id: 1, profile: { name: 'Alice', email: 'alice@test.com' } },
    { id: 2, profile: { name: 'Bob', email: 'bob@test.com' } },
  ],
  metadata: {
    total: 2,
    page: 1,
  },
};

// Extract:
// - First user's name (as 'firstUserName')
// - Second user's email (as 'secondUserEmail')
// - Total count (as 'totalUsers')

// YOUR CODE:

// ============================================
// EXERCISE 12: Chained Updates
// ============================================
// Rewrite using compound assignment operators

let value = 100;

// Rewrite these using compound operators:
// value = value + 50;
// value = value * 2;
// value = value - 100;
// value = value / 5;
// value = value % 30;

// YOUR CODE:

// ============================================
// EXERCISE 13: Safe Property Update
// ============================================
// Create a function that safely updates nested object properties

function safeUpdate(obj, path, value) {
  // path is a string like "user.address.city"
  // Create intermediate objects if they don't exist
  // Set the final value
  // YOUR CODE:
}

// Tests:
// let obj = {};
// safeUpdate(obj, "user.address.city", "NYC");
// // obj = { user: { address: { city: "NYC" } } }

// ============================================
// EXERCISE 14: Accumulator Patterns
// ============================================
// Use compound assignment to calculate:

const transactions = [
  { type: 'credit', amount: 100 },
  { type: 'debit', amount: 50 },
  { type: 'credit', amount: 200 },
  { type: 'debit', amount: 75 },
];

// Calculate:
// - totalCredits
// - totalDebits
// - balance (credits - debits)

// YOUR CODE:

// ============================================
// EXERCISE 15: Rest and Spread Assignment
// ============================================
// Use destructuring with rest to separate data

const fullRecord = {
  id: 123,
  createdAt: '2024-01-01',
  updatedAt: '2024-06-15',
  name: 'Widget',
  price: 29.99,
  category: 'Electronics',
  inStock: true,
};

// Separate into:
// - metadata (id, createdAt, updatedAt)
// - productData (everything else)

// YOUR CODE:

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

/*

// SOLUTION 1: Compound Assignment
let a = 10;
a += 5;      // a = 15
a *= 2;      // a = 30
a -= 10;     // a = 20
a /= 4;      // a = 5
a %= 3;      // a = 2


// SOLUTION 2: String Building
let greeting = "";
greeting += "Hello";
greeting += ", ";
greeting += "World";
greeting += "! ";
greeting += "How are you?";
// or: greeting += "Hello" + ", " + "World" + "! " + "How are you?";


// SOLUTION 3: Logical Assignment Predictions
// b1 = 10 (5 is truthy, so assign 10)
// b2 = 0 (0 is falsy, so don't assign)
// b3 = "default" ("" is falsy, so assign)
// b4 = "hello" ("hello" is truthy, so don't assign)
// b5 = "fallback" (null, so assign)
// b6 = 0 (0 is not nullish, so don't assign)


// SOLUTION 4: Array Destructuring
const [primary, secondary1, secondary2, ...others] = colors;


// SOLUTION 5: Object Destructuring
const {
    name: personName,
    age = 0,
    address: { city },
    hobbies
} = person;


// SOLUTION 6: Swap Variables
[x, y] = [y, x];


// SOLUTION 7: Function with Destructured Parameters
function createServer({ port = 3000, host = "localhost", secure = false } = {}) {
    const protocol = secure ? "https" : "http";
    return `${protocol}://${host}:${port}`;
}


// SOLUTION 8: Counter Class
function createCounter(initial = 0) {
    let count = initial;
    return {
        get value() { return count; },
        increment(n = 1) { count += n; },
        decrement(n = 1) { count -= n; },
        reset() { count = initial; },
        double() { count *= 2; }
    };
}


// SOLUTION 9: Config Merger
function mergeWithDefaults(config) {
    config.timeout ??= 5000;
    config.retries ??= 3;
    config.debug ??= false;
    config.maxConnections ??= 10;
    return config;
}


// SOLUTION 10: Multiple Return Values
function getStats(numbers) {
    if (!numbers.length) {
        return { min: 0, max: 0, sum: 0, average: 0, count: 0 };
    }
    
    const sum = numbers.reduce((a, b) => a + b, 0);
    return {
        min: Math.min(...numbers),
        max: Math.max(...numbers),
        sum,
        average: sum / numbers.length,
        count: numbers.length
    };
}


// SOLUTION 11: Deep Destructuring
const {
    users: [
        { profile: { name: firstUserName } },
        { profile: { email: secondUserEmail } }
    ],
    metadata: { total: totalUsers }
} = data;


// SOLUTION 12: Chained Updates
let value = 100;
value += 50;   // 150
value *= 2;    // 300
value -= 100;  // 200
value /= 5;    // 40
value %= 30;   // 10


// SOLUTION 13: Safe Property Update
function safeUpdate(obj, path, value) {
    const keys = path.split('.');
    let current = obj;
    
    for (let i = 0; i < keys.length - 1; i++) {
        current[keys[i]] ??= {};
        current = current[keys[i]];
    }
    
    current[keys[keys.length - 1]] = value;
    return obj;
}


// SOLUTION 14: Accumulator Patterns
let totalCredits = 0;
let totalDebits = 0;

for (const t of transactions) {
    if (t.type === "credit") {
        totalCredits += t.amount;
    } else {
        totalDebits += t.amount;
    }
}

let balance = totalCredits - totalDebits;
// totalCredits = 300, totalDebits = 125, balance = 175


// SOLUTION 15: Rest and Spread Assignment
const { id, createdAt, updatedAt, ...productData } = fullRecord;
const metadata = { id, createdAt, updatedAt };
// metadata = { id: 123, createdAt: "2024-01-01", updatedAt: "2024-06-15" }
// productData = { name: "Widget", price: 29.99, category: "Electronics", inStock: true }

*/
Exercises - JavaScript Tutorial | DeepML