Object Methods, Getters, Setters and Copying

Work with objects using Object.keys, values, entries, assign and freeze, add getters and setters, and copy objects safely with spread and structuredClone.

Lesson 27 of 56Intermediate15 min read

You already know how to create objects and read their properties. Real programs need more: loop over every property, turn an object into a list and back, merge default settings with user choices, lock an object so it can't be changed, and copy an object without the copy secretly sharing data with the original.

JavaScript's built-in Object helpers handle all of this. Object.keys, Object.values and Object.entries turn an object into arrays you can loop over and use with map and filter. Object.fromEntries turns them back. Object.assign and the spread syntax merge objects, and Object.freeze makes them read-only.

You'll also learn getters and setters, which look like ordinary properties but run code when read or written, and the most important idea of all: the difference between a shallow copy and a deep copy. Many confusing bugs come from changing a "copy" and accidentally changing the original too. structuredClone fixes that.

Turning objects into arrays and back

MethodReturnsFor { a: 1, b: 2 }
Object.keys(obj)Array of keys["a", "b"]
Object.values(obj)Array of values[1, 2]
Object.entries(obj)Array of [key, value] pairs[["a", 1], ["b", 2]]
Object.fromEntries(pairs)An object from pairs{ a: 1, b: 2 }

The pattern entries, then an array method, then fromEntries transforms an object in one line:

JavaScript
const prices = { tea: 2, cake: 3 };
const withTax = Object.fromEntries(
  Object.entries(prices).map(([item, p]) => [item, p * 1.2])
);

Merging, checking and locking

MethodDoes
{ ...defaults, ...options }Merges into a new object; later properties win
Object.assign(target, source)Copies properties into target (changes it)
Object.hasOwn(obj, "key")Is the property on the object itself?
"key" in objIs it on the object or its prototype?
delete obj.keyRemoves a property
Object.freeze(obj)Makes properties read-only; changes are ignored, or throw in strict mode
Object.isFrozen(obj)Checks if an object is frozen

Object.freeze is shallow: nested objects inside a frozen object can still change.

Getters and setters

JavaScript
const user = {
  first: "Ana",
  last: "Silva",
  get fullName() { return `${this.first} ${this.last}`; },
  set fullName(value) { [this.first, this.last] = value.split(" "); },
};

user.fullName;              // "Ana Silva", no brackets
user.fullName = "Ben Cole"; // runs the setter
  • A getter (get) runs when the property is read. Use it for values calculated from other properties, so they're never out of date.
  • A setter (set) runs when the property is assigned. Use it to validate or convert values.
  • You read and write them like normal properties, without calling them. They work the same way in classes.

Shallow vs deep copies

TechniqueCopies nested objects?
const b = aNo: b is the same object
{ ...a }, Object.assign({}, a)Top level only (shallow)
structuredClone(a)Yes, every level (deep)
JSON.parse(JSON.stringify(a))Yes, but loses dates, functions, undefined, Maps and Sets

With a shallow copy, nested objects and arrays are still shared, so changing copy.address.city also changes the original. structuredClone is built into every modern browser and copies dates, Maps, Sets and nested data correctly. It can't copy functions or DOM elements.

JavaScript Object Methods Syntax

Object helpers

Object.keys(obj); Object.values(obj); Object.entries(obj);
Object.fromEntries([["a", 1]]);
const merged = { ...defaults, ...settings };
Object.hasOwn(obj, "id");
Object.freeze(config);
const copy = structuredClone(original);
const temp = { c: 20, get f() { return this.c * 9 / 5 + 32; } };

JavaScript Object Methods Summary

  • Object.keys, values and entries turn objects into arrays; fromEntries turns pairs back.
  • Spread { ...a, ...b } merges objects; later properties win.
  • Object.freeze makes an object read-only, but only one level deep.
  • Getters calculate values when read; setters run code when written.
  • Spread copies are shallow; structuredClone makes a deep copy.

JavaScript Object Methods Examples

Each example runs in the page. Edit the code and press Run to see what changes.

Example 1

Looping and transforming objects

const scores = { maths: 72, english: 88, science: 65, art: 91 };

for (const [subject, score] of Object.entries(scores)) {
  console.log(`${subject.padEnd(8)} ${score}`);
}

const total = Object.values(scores).reduce((sum, s) => sum + s, 0);
console.log("Average:", total / Object.keys(scores).length);

const passed = Object.fromEntries(
  Object.entries(scores).filter(([, score]) => score >= 70)
);
console.log("Passed:", passed);
ConsoleEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 3entries gives each subject and score together.
  2. Lines 7 to 8values and keys give arrays you can total and count.
  3. Lines 10 to 12Filter the pairs, then rebuild an object with only the passing subjects.
Example 2

Defaults, freezing and getters

const defaults = Object.freeze({ theme: "light", fontSize: 16, sound: true });
const saved = { fontSize: 18 };

const settings = { ...defaults, ...saved };
console.log(settings);

defaults.theme = "dark";
console.log("Frozen still light:", defaults.theme, Object.isFrozen(defaults));

const temperature = {
  celsius: 20,
  get fahrenheit() { return this.celsius * 9 / 5 + 32; },
  set fahrenheit(f) { this.celsius = Math.round((f - 32) * 5 / 9); },
};
console.log(temperature.fahrenheit);
temperature.fahrenheit = 212;
console.log(temperature.celsius);
ConsoleEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 1Defaults are frozen so nothing can change them.
  2. Line 4The saved font size overrides the default; the rest is kept.
  3. Line 7Assigning to a frozen object is ignored (or throws in strict mode).
  4. Line 12The getter calculates Fahrenheit whenever it's read.
  5. Line 13The setter converts a Fahrenheit value back to Celsius.
Example 3

Shallow vs deep copies

const original = {
  name: "Ana",
  address: { city: "Lisbon" },
  joined: new Date(2024, 0, 15),
};

const shallow = { ...original };
shallow.name = "Bea";
shallow.address.city = "Porto";
console.log("Original city after shallow copy:", original.address.city);

const deep = structuredClone(original);
deep.address.city = "Faro";
console.log("Original city after deep copy:", original.address.city);
console.log("Date kept as a Date:", deep.joined instanceof Date);
ConsoleEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 7Spread copies the top level only.
  2. Line 8Changing a top-level property on the copy is safe.
  3. Lines 9 to 10But address is shared, so the original's city changes too.
  4. Lines 12 to 14structuredClone copies every level, so the original is untouched.
  5. Line 15Dates stay real Date objects, unlike with JSON.

Common JavaScript Object Methods Mistakes

Calling a getter like a function

Don't
user.fullName(); // TypeError: not a function
Do
user.fullName;

Thinking spread makes a deep copy

Don't
const copy = { ...order };
copy.items.push("extra"); // also changes order.items
Do
const copy = structuredClone(order);
copy.items.push("extra");

Mutating the target with Object.assign

Don't
const merged = Object.assign(defaults, options); // defaults is changed
Do
const merged = Object.assign({}, defaults, options);
// or
const merged2 = { ...defaults, ...options };

JavaScript Object Methods in Real Projects

Object helpers in real projects

Config systems merge defaults with user settings using spread. Forms turn Object.fromEntries(new FormData(form)) into a plain object ready to send. State libraries such as Redux require new objects instead of changes, and use Object.freeze in development to catch mistakes. Undo features save snapshots with structuredClone.

JavaScript Object Methods Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Get an array of the object's keys.

const car = { make: "Mini", year: 2020 };
console.log(Object.(car));
Predict the outputmedium

What is logged?

const a = { list: [1] };
const b = { ...a };
b.list.push(2);
console.log(a.list.length, a === b);
Multiple choiceeasy

Which makes a deep copy of nested data?

Multiple choicemedium

What does a getter do?

Fix the bugmedium

withDiscount(product, percent) should return a new product with a lower price, leaving the original and its nested tags array unchanged. Also, product.label should be a getter. Fix it.

const product = {
  name: "Lamp",
  price: 40,
  tags: ["home"],
  label() { return `${this.name} £${this.price}`; },
};
function withDiscount(item, percent) {
  const copy = item;
  copy.price = item.price * (1 - percent / 100);
  copy.tags.push("sale");
  return copy;
}
const sale = withDiscount(product, 25);
console.log(sale.price, product.price, product.tags);
ConsoleEdit the code, then press Run or Ctrl+Enter
Checks
  • Discounted copy
  • Original price unchanged
  • Original tags unchanged
  • label is a getter

JavaScript Object Methods Quiz

5 questions to check what you learned.

  1. What does Object.values({ a: 1, b: 2 }) return?

    • ["a", "b"]
    • [1, 2]
    • [["a", 1], ["b", 2]]
    • 2
  2. In { ...a, ...b }, which value wins if both have the same key?

    • a's
    • b's, because it comes later
    • Neither, it's an error
    • The larger one
  3. Is Object.freeze deep?

    • No, nested objects can still change
    • Yes, every level
    • Only for arrays
    • Only in strict mode
  4. What does JSON.parse(JSON.stringify(obj)) lose?

    • Strings
    • Numbers
    • Nothing
    • Functions, undefined values, and Date objects (which become strings)
  5. What's the difference between Object.hasOwn(obj, "x") and "x" in obj?

    • None
    • hasOwn checks only the object itself; in also checks its prototype chain
    • in only works on arrays
    • hasOwn checks values

JavaScript Object Methods Challenge

A shopping basket object

Create an object basket with:

  1. items: an array of { name, price, qty } objects, starting empty
  2. A method add(name, price, qty = 1) that pushes an item
  3. A getter total that returns the sum of price * qty for all items
  4. A getter count that returns the total quantity
  5. A method snapshot() that returns a deep copy of items using structuredClone
ConsoleEdit the code, then press Run or Ctrl+Enter
Checks
  • add and total
  • count of all quantities
  • total and count are getters
  • snapshot is a deep copy