javascript

exercises

exercises.js
/**
 * ============================================
 * 7.1 OBJECT BASICS - EXERCISES
 * ============================================
 *
 * Practice creating, accessing, and manipulating objects.
 */

/**
 * EXERCISE 1: Create an Object
 * ----------------------------
 * Create an object representing a book.
 */

console.log('=== Exercise 1: Create an Object ===');

// Create a book object with:
// - title: "JavaScript: The Good Parts"
// - author: "Douglas Crockford"
// - year: 2008
// - pages: 176
// - isAvailable: true

const book = {
  // YOUR CODE HERE
};

console.log('Book:', book);

/*
 * SOLUTION:
 */
const bookSolution = {
  title: 'JavaScript: The Good Parts',
  author: 'Douglas Crockford',
  year: 2008,
  pages: 176,
  isAvailable: true,
};
console.log('Book Solution:', bookSolution);

/**
 * EXERCISE 2: Access Properties
 * -----------------------------
 * Access various properties using both notations.
 */

console.log('\n=== Exercise 2: Access Properties ===');

const product = {
  'product-name': 'Laptop',
  brand: 'TechBrand',
  'price-usd': 999,
  specs: {
    cpu: 'Intel i7',
    ram: '16GB',
  },
};

// Access "product-name" (use bracket notation)
const productName = null; // YOUR CODE

// Access "brand" (use dot notation)
const brandName = null; // YOUR CODE

// Access "price-usd" using a variable
const priceField = 'price-usd';
const price = null; // YOUR CODE

// Access nested "cpu" property
const cpu = null; // YOUR CODE

console.log('Product:', productName);
console.log('Brand:', brandName);
console.log('Price:', price);
console.log('CPU:', cpu);

/*
 * SOLUTION:
 * const productName = product["product-name"];
 * const brandName = product.brand;
 * const price = product[priceField];
 * const cpu = product.specs.cpu;
 */

/**
 * EXERCISE 3: Dynamic Properties
 * ------------------------------
 * Create an object with computed property names.
 */

console.log('\n=== Exercise 3: Dynamic Properties ===');

const prefix = 'user';
const id = 42;

// Create an object with these computed properties:
// - userName: "Alice"
// - userId: 42
// - user42_status: "active"

const userData = {
  // YOUR CODE HERE
};

console.log('User data:', userData);

/*
 * SOLUTION:
 */
const userDataSolution = {
  [`${prefix}Name`]: 'Alice',
  [`${prefix}Id`]: id,
  [`${prefix}${id}_status`]: 'active',
};
console.log('User data solution:', userDataSolution);

/**
 * EXERCISE 4: Property Shorthand
 * ------------------------------
 * Use ES6 shorthand syntax.
 */

console.log('\n=== Exercise 4: Property Shorthand ===');

const firstName = 'John';
const lastName = 'Doe';
const email = 'john@example.com';
const age = 25;

// Create an object using shorthand property syntax
const profile = null; // YOUR CODE: { firstName, lastName, ... }

console.log('Profile:', profile);

/*
 * SOLUTION:
 * const profile = { firstName, lastName, email, age };
 */

/**
 * EXERCISE 5: Add and Modify Properties
 * -------------------------------------
 * Dynamically add and modify object properties.
 */

console.log('\n=== Exercise 5: Add and Modify ===');

const car = {
  brand: 'Honda',
  model: 'Civic',
};

// 1. Add a "year" property with value 2023
// 2. Add a "color" property with value "blue"
// 3. Change "model" to "Accord"
// 4. Add a nested "engine" object with { type: "V6", hp: 280 }

// YOUR CODE HERE

console.log('Modified car:', car);

/*
 * SOLUTION:
 * car.year = 2023;
 * car["color"] = "blue";
 * car.model = "Accord";
 * car.engine = { type: "V6", hp: 280 };
 */

/**
 * EXERCISE 6: Check for Properties
 * --------------------------------
 * Use different methods to check if properties exist.
 */

console.log('\n=== Exercise 6: Check Properties ===');

const config = {
  timeout: 0,
  retries: undefined,
  debug: false,
};

// Check if each property exists using 'in' operator
const hasTimeout = null; // YOUR CODE
const hasRetries = null; // YOUR CODE
const hasMaxSize = null; // YOUR CODE

// Check if 'timeout' is an OWN property (not inherited)
const ownsTimeout = null; // YOUR CODE

console.log('Has timeout:', hasTimeout); // true
console.log('Has retries:', hasRetries); // true
console.log('Has maxSize:', hasMaxSize); // false
console.log('Owns timeout:', ownsTimeout); // true

/*
 * SOLUTION:
 * const hasTimeout = "timeout" in config;
 * const hasRetries = "retries" in config;
 * const hasMaxSize = "maxSize" in config;
 * const ownsTimeout = config.hasOwnProperty("timeout");
 */

/**
 * EXERCISE 7: Delete Properties
 * -----------------------------
 * Remove unwanted properties.
 */

console.log('\n=== Exercise 7: Delete Properties ===');

const userProfile = {
  id: 1,
  name: 'Alice',
  password: 'secret123',
  email: 'alice@example.com',
  _internal: 'debug data',
};

// Delete the 'password' and '_internal' properties
// YOUR CODE HERE

console.log('Cleaned profile:', userProfile);
console.log('Password exists:', 'password' in userProfile); // false

/*
 * SOLUTION:
 * delete userProfile.password;
 * delete userProfile._internal;
 */

/**
 * EXERCISE 8: Optional Chaining
 * -----------------------------
 * Safely access nested properties.
 */

console.log('\n=== Exercise 8: Optional Chaining ===');

const response = {
  data: {
    users: [
      { name: 'Alice', profile: { avatar: 'alice.jpg' } },
      { name: 'Bob' },
    ],
  },
};

// Safely access Alice's avatar
const aliceAvatar = null; // YOUR CODE (should be "alice.jpg")

// Safely access Bob's avatar (doesn't exist)
const bobAvatar = null; // YOUR CODE (should be undefined)

// Safely access a non-existent path
const missingData = null; // YOUR CODE: response.missing?.deep?.value

console.log('Alice avatar:', aliceAvatar);
console.log('Bob avatar:', bobAvatar);
console.log('Missing data:', missingData);

/*
 * SOLUTION:
 * const aliceAvatar = response.data?.users?.[0]?.profile?.avatar;
 * const bobAvatar = response.data?.users?.[1]?.profile?.avatar;
 * const missingData = response.missing?.deep?.value;
 */

/**
 * EXERCISE 9: Nullish Coalescing
 * ------------------------------
 * Provide default values correctly.
 */

console.log('\n=== Exercise 9: Nullish Coalescing ===');

const settings = {
  volume: 0, // Valid: 0 means muted
  brightness: null, // Needs default
  theme: '', // Valid: empty means default theme
  language: undefined, // Needs default
};

// Use ?? to get values with proper defaults
const volume = null; // YOUR CODE: settings.volume ?? 50
const brightness = null; // YOUR CODE: settings.brightness ?? 100
const theme = null; // YOUR CODE: settings.theme ?? "dark"
const language = null; // YOUR CODE: settings.language ?? "en"

console.log('Volume:', volume); // 0 (not 50!)
console.log('Brightness:', brightness); // 100
console.log('Theme:', theme); // "" (not "dark"!)
console.log('Language:', language); // "en"

/*
 * SOLUTION:
 * const volume = settings.volume ?? 50;
 * const brightness = settings.brightness ?? 100;
 * const theme = settings.theme ?? "dark";
 * const language = settings.language ?? "en";
 */

/**
 * EXERCISE 10: Build an Object Factory
 * ------------------------------------
 * Create a function that builds user objects.
 */

console.log('\n=== Exercise 10: Object Factory ===');

function createUser(name, email, options = {}) {
  // Create and return a user object with:
  // - id: random number
  // - name: from parameter
  // - email: from parameter
  // - role: from options or default "user"
  // - createdAt: current date

  // YOUR CODE HERE
  return {};
}

const newUser = createUser('Alice', 'alice@example.com', { role: 'admin' });
console.log('New user:', newUser);

/*
 * SOLUTION:
 */
function createUserSolution(name, email, options = {}) {
  return {
    id: Math.floor(Math.random() * 10000),
    name,
    email,
    role: options.role ?? 'user',
    createdAt: new Date(),
  };
}
console.log('Solution user:', createUserSolution('Bob', 'bob@example.com'));

/**
 * EXERCISE 11: Merge Objects
 * --------------------------
 * Combine multiple objects.
 */

console.log('\n=== Exercise 11: Merge Objects ===');

const defaults = {
  theme: 'light',
  fontSize: 14,
  showSidebar: true,
};

const userPrefs = {
  theme: 'dark',
  fontSize: 16,
};

// Merge defaults and userPrefs (userPrefs should override)
const finalSettings = null; // YOUR CODE: use spread operator

console.log('Final settings:', finalSettings);

/*
 * SOLUTION:
 * const finalSettings = { ...defaults, ...userPrefs };
 */

/**
 * EXERCISE 12: Object Destructuring with Defaults
 * ------------------------------------------------
 * Extract values with default fallbacks.
 */

console.log('\n=== Exercise 12: Destructuring ===');

const apiResponse = {
  status: 200,
  data: { items: [1, 2, 3] },
  // error is missing
};

// Destructure with defaults:
// - status (no default needed)
// - data (no default needed)
// - error (default to null)
// - message (default to "Success")

// YOUR CODE: const { status, ... } = apiResponse;

// console.log("Status:", status);
// console.log("Data:", data);
// console.log("Error:", error);     // null
// console.log("Message:", message); // "Success"

/*
 * SOLUTION:
 */
const { status, data, error = null, message = 'Success' } = apiResponse;

console.log('Status:', status);
console.log('Data:', data);
console.log('Error:', error);
console.log('Message:', message);

/**
 * EXERCISE 13: Count Properties
 * -----------------------------
 * Write a function to count object properties.
 */

console.log('\n=== Exercise 13: Count Properties ===');

function countProperties(obj) {
  // Return the number of own properties
  // YOUR CODE HERE
  return 0;
}

const testObj = { a: 1, b: 2, c: 3, d: 4 };
console.log('Property count:', countProperties(testObj)); // 4

/*
 * SOLUTION:
 */
function countPropertiesSolution(obj) {
  return Object.keys(obj).length;
}
console.log('Solution count:', countPropertiesSolution(testObj));

/**
 * EXERCISE 14: Filter Object Properties
 * -------------------------------------
 * Create a new object with only specified keys.
 */

console.log('\n=== Exercise 14: Filter Properties ===');

function pick(obj, keys) {
  // Return new object with only the specified keys
  // YOUR CODE HERE
  return {};
}

const fullUser = {
  id: 1,
  name: 'Alice',
  email: 'alice@example.com',
  password: 'secret',
  createdAt: '2023-01-01',
};

const publicUser = pick(fullUser, ['id', 'name', 'email']);
console.log('Public user:', publicUser);

/*
 * SOLUTION:
 */
function pickSolution(obj, keys) {
  const result = {};
  for (const key of keys) {
    if (key in obj) {
      result[key] = obj[key];
    }
  }
  return result;
}
console.log('Solution pick:', pickSolution(fullUser, ['id', 'name', 'email']));

/**
 * EXERCISE 15: Transform Object
 * -----------------------------
 * Transform an object using a mapping function.
 */

console.log('\n=== Exercise 15: Transform Object ===');

function mapObject(obj, fn) {
  // Apply fn to each value, return new object
  // fn receives (value, key)
  // YOUR CODE HERE
  return {};
}

const prices = {
  apple: 1.5,
  banana: 0.75,
  orange: 2.0,
};

const doublePrices = mapObject(prices, (value) => value * 2);
console.log('Double prices:', doublePrices);

const labeledPrices = mapObject(prices, (value, key) => `${key}: $${value}`);
console.log('Labeled prices:', labeledPrices);

/*
 * SOLUTION:
 */
function mapObjectSolution(obj, fn) {
  const result = {};
  for (const [key, value] of Object.entries(obj)) {
    result[key] = fn(value, key);
  }
  return result;
}
console.log(
  'Solution doubled:',
  mapObjectSolution(prices, (v) => v * 2)
);

console.log('\n=== Exercises Complete ===');
Exercises - JavaScript Tutorial | DeepML