JavaScript Object Practice Programs with Solutions (32 Programs)

Practise JavaScript objects with 32 programs, each with a full solution, the exact output and a short explanation. The programs start with the basics, move to intermediate problems and finish with real-world scenarios from test automation, such as test data, prices, form inputs and test results. They are written for testers learning JavaScript for Playwright.

Advertisement

How to practise: read the task, write your own solution first, then open Show solution to compare. Run any program with node program.js.

New to this topic? Read the JavaScript Objects lesson first.

JavaScript Beginner Programs

1. Create and read an objectBeginner

Create a user object with name, role and active, then print each property.

Show solution
const user = { name: 'Asha', role: 'tester', active: true };
console.log(user.name);
console.log(user['role']);
console.log(user.active);

Output

Asha
tester
true

Explanation: dot notation is the usual way to read properties. Bracket notation also works, and is needed for dynamic keys.

2. Add, update and delete propertiesBeginner

Add an email, change the role and delete active from a user object.

Show solution
const user = { name: 'Asha', role: 'tester', active: true };
user.email = 'asha@test.com';
user.role = 'lead';
delete user.active;
console.log(user);

Output

{ name: 'Asha', role: 'lead', email: 'asha@test.com' }

Explanation: objects are mutable, so properties can be added, changed or removed after creation.

3. Dynamic property namesBeginner

Read a property whose name is stored in a variable.

Show solution
const settings = { browser: 'chromium', retries: 2 };
const key = 'retries';
console.log(settings[key]);
console.log(settings.key);

Output

2
undefined

Explanation: settings[key] uses the variable’s value. settings.key looks for a property literally called key.

4. Check whether a property existsBeginner

Check for retries and proxy with in and Object.hasOwn.

Show solution
const config = { retries: 0 };
console.log('retries' in config);
console.log(Object.hasOwn(config, 'proxy'));
console.log(config.retries !== undefined);

Output

true
false
true

Explanation: in and Object.hasOwn check existence even when the value is falsy, such as 0.

5. Keys, values and entriesBeginner

Print the keys, values and entries of a test-case object.

Show solution
const testCase = { id: 'TC-1', priority: 'high', automated: true };
console.log(Object.keys(testCase));
console.log(Object.values(testCase));
console.log(Object.entries(testCase).length);

Output

[ 'id', 'priority', 'automated' ]
[ 'TC-1', 'high', true ]
3

Explanation: these methods turn an object into arrays that you can loop over or transform.

6. Loop over an objectBeginner

Print each property of a config object as key: value.

Show solution
const config = { browser: 'firefox', headless: false, workers: 2 };
for (const [key, value] of Object.entries(config)) {
  console.log(`${key}: ${value}`);
}

Output

browser: firefox
headless: false
workers: 2

Explanation: Object.entries with for...of and destructuring gives both key and value on each pass.

7. Object with a methodBeginner

Create a calculator object with add and subtract methods.

Show solution
const calculator = {
  add(a, b) { return a + b; },
  subtract(a, b) { return a - b; }
};
console.log(calculator.add(10, 5));
console.log(calculator.subtract(10, 5));

Output

15
5

Explanation: functions stored on an object are called methods.

8. Using this in a methodBeginner

Create a user object whose describe method uses this.

Show solution
const user = {
  name: 'Ravi',
  role: 'admin',
  describe() {
    return `${this.name} is an ${this.role}`;
  }
};
console.log(user.describe());

Output

Ravi is an admin

Explanation: inside a regular method, this refers to the object the method was called on.

9. Shorthand propertiesBeginner

Build an object from variables using shorthand property names.

Show solution
const browser = 'webkit';
const viewport = '1280x720';
const project = { browser, viewport };
console.log(project);

Output

{ browser: 'webkit', viewport: '1280x720' }

Explanation: { browser } is shorthand for { browser: browser } when the variable and property share a name.

10. Nested objectsBeginner

Read nested properties from an order object.

Show solution
const order = { id: 501, customer: { name: 'Meera', address: { city: 'Pune' } } };
console.log(order.customer.name);
console.log(order.customer.address.city);

Output

Meera
Pune

Explanation: chain property access to reach nested values.

JavaScript Intermediate Programs

11. Object destructuring with defaultsIntermediate

Destructure an options object with defaults and a renamed property.

Show solution
const options = { timeout: 5000, headless: false };
const { timeout, headless = true, retries = 1, timeout: waitMs } = options;
console.log(timeout, headless, retries, waitMs);

Output

5000 false 1 5000

Explanation: defaults apply only when a property is undefined. timeout: waitMs copies the same value into a new name.

12. Merge objects with spreadIntermediate

Merge default settings with overrides, keeping the overrides.

Show solution
const defaults = { browser: 'chromium', retries: 0, video: 'off' };
const overrides = { retries: 2, video: 'on' };
const merged = { ...defaults, ...overrides };
console.log(merged);

Output

{ browser: 'chromium', retries: 2, video: 'on' }

Explanation: later spreads overwrite earlier properties with the same name.

13. Shallow vs deep copyIntermediate

Show that a spread copy shares nested objects, and fix it with structuredClone.

Show solution
const original = { name: 'cart', items: ['pen'] };
const shallow = { ...original };
const deep = structuredClone(original);
shallow.items.push('book');
deep.items.push('bag');
console.log(original.items);
console.log(deep.items);

Output

[ 'pen', 'book' ]
[ 'pen', 'bag' ]

Explanation: spread copies only the top level. structuredClone copies nested data too.

14. Freeze and sealIntermediate

Compare Object.freeze and Object.seal.

Show solution
const frozen = Object.freeze({ env: 'qa' });
const sealed = Object.seal({ env: 'qa' });
frozen.env = 'prod';
sealed.env = 'prod';
sealed.extra = true;
console.log(frozen.env, sealed.env, 'extra' in sealed);

Output

qa prod false

Explanation: frozen objects cannot change at all. Sealed objects allow value changes but no new or deleted properties.

15. Count propertiesIntermediate

Count how many properties an object has.

Show solution
const response = { id: 1, name: 'Item', price: 99, inStock: true };
console.log(Object.keys(response).length);

Output

4

Explanation: objects have no length, so count their keys instead.

16. Transform an objectIntermediate

Apply a 10% discount to every price in a price list object.

Show solution
const prices = { pen: 20, book: 350, bag: 900 };
const discounted = Object.fromEntries(
  Object.entries(prices).map(([item, price]) => [item, price * 0.9])
);
console.log(discounted);

Output

{ pen: 18, book: 315, bag: 810 }

Explanation: convert to entries, map them, and convert back with Object.fromEntries.

17. Filter object propertiesIntermediate

Keep only the settings whose values are not null.

Show solution
const settings = { browser: 'chromium', proxy: null, retries: 2, baseURL: null };
const cleaned = Object.fromEntries(Object.entries(settings).filter(([, value]) => value !== null));
console.log(cleaned);

Output

{ browser: 'chromium', retries: 2 }

Explanation: filtering entries is the object equivalent of array.filter.

18. Compare two objectsIntermediate

Write a function that checks whether two flat objects have the same keys and values.

Show solution
function shallowEqual(a, b) {
  const keysA = Object.keys(a);
  const keysB = Object.keys(b);
  if (keysA.length !== keysB.length) return false;
  return keysA.every(key => a[key] === b[key]);
}
console.log(shallowEqual({ x: 1, y: 2 }, { y: 2, x: 1 }));
console.log(shallowEqual({ x: 1 }, { x: '1' }));

Output

true
false

Explanation: === compares object references, so content equality needs a key-by-key check.

19. Getters and settersIntermediate

Create an object with a fullName getter and setter.

Show solution
const person = {
  first: 'Asha',
  last: 'Sharma',
  get fullName() { return `${this.first} ${this.last}`; },
  set fullName(value) { [this.first, this.last] = value.split(' '); }
};
console.log(person.fullName);
person.fullName = 'Neha Verma';
console.log(person.first, person.last);

Output

Asha Sharma
Neha Verma

Explanation: getters and setters run code when a property is read or written, while looking like normal properties.

20. Optional chaining on missing dataIntermediate

Read a deeply nested value that may not exist.

Show solution
const responses = [
  { data: { user: { profile: { country: 'IN' } } } },
  { data: { user: null } },
  {}
];
for (const r of responses) console.log(r.data?.user?.profile?.country ?? 'unknown');

Output

IN
unknown
unknown

Explanation: ?. stops at the first null or undefined, so missing data never throws.

JavaScript Real-World QA Scenario Programs

21. Validate an API responseReal-world

Check that an API user object has all required fields with the right types.

Show solution
const required = { id: 'number', email: 'string', active: 'boolean' };
const user = { id: 12, email: 'qa@test.com', active: 'true' };
const problems = Object.entries(required)
  .filter(([field, type]) => typeof user[field] !== type)
  .map(([field, type]) => `${field} should be ${type}`);
console.log(problems.length ? problems.join('; ') : 'Response is valid');

Output

active should be boolean

Explanation: a small schema object lets one loop check every field, a lightweight contract test.

22. Build test data with defaultsReal-world

Write buildUser(overrides) that returns a default user merged with overrides.

Show solution
function buildUser(overrides = {}) {
  return { name: 'QA User', email: 'qa.user@example.com', role: 'viewer', active: true, ...overrides };
}
console.log(buildUser().role);
const admin = buildUser({ role: 'admin', name: 'Admin' });
console.log(admin.name, admin.role, admin.active);

Output

viewer
Admin admin true

Explanation: a data builder gives sensible defaults, and each test overrides only what it needs.

23. Count tests by statusReal-world

Use an object to count statuses in a results array.

Show solution
const statuses = ['passed', 'failed', 'passed', 'flaky', 'passed', 'failed'];
const counts = {};
for (const s of statuses) counts[s] = (counts[s] ?? 0) + 1;
console.log(counts);

Output

{ passed: 3, failed: 2, flaky: 1 }

Explanation: object keys work as counters, a pattern used in every test report.

24. Environment config lookupReal-world

Store base URLs per environment in an object and pick one by name.

Show solution
const environments = {
  qa: { baseURL: 'https://qa.shop.test', retries: 1 },
  staging: { baseURL: 'https://staging.shop.test', retries: 2 }
};
const envName = 'staging';
const env = environments[envName] ?? environments.qa;
console.log(env.baseURL, env.retries);

Output

https://staging.shop.test 2

Explanation: an object lookup replaces a chain of if statements and falls back to a default.

25. Map API fields to UI labelsReal-world

Rename snake_case API keys to readable labels.

Show solution
const apiUser = { first_name: 'Ravi', last_name: 'Kumar', phone_no: '9876543210' };
const labels = { first_name: 'First name', last_name: 'Last name', phone_no: 'Phone' };
for (const [key, value] of Object.entries(apiUser)) {
  console.log(`${labels[key]}: ${value}`);
}

Output

First name: Ravi
Last name: Kumar
Phone: 9876543210

Explanation: a mapping object keeps label translations in one place.

26. Diff expected vs actual objectsReal-world

Report which fields differ between expected and actual user details.

Show solution
const expected = { name: 'Asha', city: 'Delhi', plan: 'pro' };
const actual = { name: 'Asha', city: 'Mumbai', plan: 'free' };
for (const key of Object.keys(expected)) {
  if (expected[key] !== actual[key]) {
    console.log(`${key}: expected '${expected[key]}', got '${actual[key]}'`);
  }
}

Output

city: expected 'Delhi', got 'Mumbai'
plan: expected 'pro', got 'free'

Explanation: field-level differences make failed assertions much easier to understand than a plain false.

27. Group products by categoryReal-world

Group product names under their category.

Show solution
const products = [
  { name: 'Mouse', category: 'electronics' },
  { name: 'Pen', category: 'stationery' },
  { name: 'Keyboard', category: 'electronics' }
];
const groups = {};
for (const p of products) (groups[p.category] ??= []).push(p.name);
console.log(groups);

Output

{ electronics: [ 'Mouse', 'Keyboard' ], stationery: [ 'Pen' ] }

Explanation: ??= creates the array the first time a category appears, then each product is pushed into it.

28. Read headers case-insensitivelyReal-world

Find the Content-Type header regardless of letter case.

Show solution
const headers = { 'content-type': 'application/json', 'X-Request-Id': 'abc-1' };
function getHeader(all, name) {
  const key = Object.keys(all).find(k => k.toLowerCase() === name.toLowerCase());
  return key ? all[key] : undefined;
}
console.log(getHeader(headers, 'Content-Type'));
console.log(getHeader(headers, 'x-request-id'));

Output

application/json
abc-1

Explanation: HTTP header names are case-insensitive, so compare them in lower case.

29. Remove sensitive fields before loggingReal-world

Copy a user object without its password and token before printing it.

Show solution
const user = { id: 3, email: 'qa@test.com', password: 'Secret!23', token: 'abc.def' };
const { password, token, ...safeUser } = user;
console.log(safeUser);

Output

{ id: 3, email: 'qa@test.com' }

Explanation: rest destructuring collects every property except the named ones, a quick way to strip secrets.

30. Convert form data to a query stringReal-world

Turn a filter object into a URL query string, skipping empty values.

Show solution
const filters = { q: 'laptop', minPrice: 30000, brand: '', sort: 'price_asc' };
const params = new URLSearchParams(
  Object.entries(filters).filter(([, v]) => v !== '').map(([k, v]) => [k, String(v)])
);
console.log(params.toString());

Output

q=laptop&minPrice=30000&sort=price_asc

Explanation: filter out empty values, then URLSearchParams handles encoding.

31. Track a page object’s stateReal-world

Create a cart object with methods that add items and calculate the total.

Show solution
const cart = {
  items: [],
  add(name, price, qty = 1) { this.items.push({ name, price, qty }); return this; },
  total() { return this.items.reduce((sum, i) => sum + i.price * i.qty, 0); }
};
cart.add('Mouse', 599).add('Cable', 199, 2);
console.log(cart.items.length, 'items, total', cart.total());

Output

2 items, total 997

Explanation: methods share state through this, and returning this allows chaining calls.

32. Convert an array of rows into objectsReal-world

Convert CSV rows into objects using the header row as keys.

Show solution
const rows = [['id', 'user', 'status'], ['1', 'asha', 'active'], ['2', 'ravi', 'locked']];
const [header, ...data] = rows;
const records = data.map(row => Object.fromEntries(header.map((h, i) => [h, row[i]])));
console.log(records[1]);
console.log(records.length);

Output

{ id: '2', user: 'ravi', status: 'locked' }
2

Explanation: pairing each header with the value at the same index builds one object per row.

Keep Practising

Leave a Comment