Ad – 728Γ—90
πŸ“¦ Data Structures

JavaScript Objects – Keys, Values, and Methods

Objects are the foundation of JavaScript. Nearly everything in the language β€” arrays, functions, even DOM nodes β€” is an object. Understanding how to create, read, update, and iterate objects is essential for writing real-world JavaScript.

⏱️ 26 min read 🎯 Intermediate πŸ“… Updated 2026

Object Literals

The object literal {} is the most common way to create an object. A property is a key-value pair; the key is always a string (or Symbol), but the value can be anything.

JavaScript
// Basic object literal
const user = {
  name: 'Alice',
  age: 28,
  isAdmin: false,
  address: {
    city: 'London',
    country: 'UK'
  },
  hobbies: ['reading', 'coding']
};

// Keys can be multi-word strings (use quotes)
const config = {
  'max-retries': 3,
  'api-url': 'https://api.example.com'
};

// Empty object
const empty = {};

console.log(typeof user);    // 'object'
console.log(user.name);      // 'Alice'
console.log(user.address.city); // 'London'

Dot Notation vs Bracket Notation

Both notations read and write properties. Use dot notation when the key is a valid identifier; use bracket notation for dynamic keys or keys with special characters.

JavaScript
const person = { name: 'Bob', age: 30 };

// Dot notation
console.log(person.name);  // 'Bob'
person.email = 'bob@example.com'; // add property

// Bracket notation
console.log(person['age']); // 30
person['phone'] = '555-1234';

// Dynamic key (only bracket notation works here)
const key = 'name';
console.log(person[key]);   // 'Bob' β€” equivalent to person.name

// Multi-word keys require bracket notation
const cfg = { 'max-retries': 5 };
console.log(cfg['max-retries']); // 5
// console.log(cfg.max-retries); // SyntaxError

// Deleting a property
delete person.phone;
console.log(person.phone); // undefined
β–Ά Output
Bob
30
Bob
5
undefined

Object Methods and the this Keyword

When a function is stored as a property of an object, it is called a method. Inside a method, this refers to the object the method was called on.

JavaScript
const calculator = {
  value: 0,

  // Method shorthand (ES6)
  add(n) {
    this.value += n;
    return this; // enables chaining
  },
  subtract(n) {
    this.value -= n;
    return this;
  },
  result() {
    return this.value;
  }
};

const answer = calculator.add(10).add(5).subtract(3).result();
console.log(answer); // 12

// Beware: arrow functions do NOT bind their own 'this'
const counter = {
  count: 0,
  increment: () => {
    // this is the outer scope (window/undefined in strict mode)
    this.count++; // won't work as expected
  },
  decrement() {
    this.count--; // regular method β€” 'this' is counter
  }
};
πŸ’‘
Avoid Arrow Functions for Object Methods

Arrow functions inherit this from their surrounding lexical scope, not from the object. Always use regular function syntax (method() {} or method: function() {}) when you need this to refer to the object.

Object.keys, Object.values, Object.entries

JavaScript
const product = { id: 1, name: 'Laptop', price: 999 };

// Object.keys – array of property names
console.log(Object.keys(product));    // ['id', 'name', 'price']

// Object.values – array of property values
console.log(Object.values(product));  // [1, 'Laptop', 999]

// Object.entries – array of [key, value] pairs
console.log(Object.entries(product));
// [['id', 1], ['name', 'Laptop'], ['price', 999]]

// Iterating with for...of + destructuring
for (const [key, value] of Object.entries(product)) {
  console.log(`${key}: ${value}`);
}

// Convert entries back to an object
const doubled = Object.fromEntries(
  Object.entries(product).map(([k, v]) =>
    typeof v === 'number' ? [k, v * 2] : [k, v]
  )
);
console.log(doubled); // { id: 2, name: 'Laptop', price: 1998 }

Object.assign and Spread

JavaScript
const defaults = { theme: 'light', lang: 'en', debug: false };
const userPrefs = { theme: 'dark', notifications: true };

// Object.assign – copies properties into target (mutates target)
const merged1 = Object.assign({}, defaults, userPrefs);
// { theme: 'dark', lang: 'en', debug: false, notifications: true }

// Spread operator – cleaner, preferred in modern code
const merged2 = { ...defaults, ...userPrefs };
// { theme: 'dark', lang: 'en', debug: false, notifications: true }

// Shallow copy with spread
const original = { a: 1, nested: { b: 2 } };
const copy = { ...original };
copy.a = 99;
copy.nested.b = 99; // mutates ORIGINAL.nested too β€” it's a shallow copy!
console.log(original.nested.b); // 99 ← shared reference

// Shorthand properties (ES6)
const name = 'Carol';
const age = 25;
const person = { name, age }; // same as { name: name, age: age }
console.log(person); // { name: 'Carol', age: 25 }

// Computed property names
const fieldName = 'email';
const dynamic = { [fieldName]: 'carol@example.com' };
console.log(dynamic); // { email: 'carol@example.com' }

Checking Property Existence

JavaScript
const obj = { name: 'Alice', role: undefined };

// in operator – checks own + inherited properties
console.log('name' in obj);     // true
console.log('role' in obj);     // true (even though value is undefined)
console.log('toString' in obj); // true (inherited from Object.prototype)

// hasOwnProperty – own properties only
console.log(obj.hasOwnProperty('name'));     // true
console.log(obj.hasOwnProperty('toString')); // false

// Object.hasOwn (ES2022 – preferred over hasOwnProperty)
console.log(Object.hasOwn(obj, 'name'));  // true
console.log(Object.hasOwn(obj, 'email')); // false

// Optional chaining for safe nested access
const config = { db: { host: 'localhost' } };
console.log(config?.db?.port);    // undefined (no error)
console.log(config?.cache?.host); // undefined (no error)

Object.freeze and Object.seal

OperationObject.freeze()Object.seal()Normal Object
Add propertiesNoNoYes
Delete propertiesNoNoYes
Change valuesNoYesYes
Check withObject.isFrozen()Object.isSealed()β€”
πŸ’‘
Freeze is Shallow

Object.freeze() only prevents changes to the top-level properties. Nested objects remain mutable. For a deep freeze you need a recursive utility function.

Interview Questions

  • What is the difference between dot notation and bracket notation?
  • Why does this behave differently in arrow functions vs regular methods?
  • What is the difference between Object.freeze() and Object.seal()?
  • How do you check if a property exists on an object vs its prototype?
  • What is the output of Object.keys({ a: 1, b: undefined })?
  • How does spread-based object copying differ from Object.assign?

πŸ‹οΈ Practical Exercise

Create a bankAccount object with properties owner (string), balance (number), and methods deposit(amount), withdraw(amount) (prevent negative balance), and statement() (returns a formatted string). Test all three methods.

πŸ”₯ Challenge Exercise

Write a function deepFreeze(obj) that recursively freezes an object and all of its nested objects so that no property at any depth can be modified. Ensure it handles arrays and circular references safely.

Frequently Asked Questions

Is null an object?
typeof null === 'object' is a historic JavaScript bug. null is not an object; it represents the intentional absence of any value. Always check for null explicitly: if (value !== null && typeof value === 'object').
What is the difference between Object.assign and spread?
Both perform shallow merges. Object.assign mutates the target object; spread always creates a new object. Spread is generally preferred in modern code for its clarity.
Can object keys be numbers?
Keys are always coerced to strings (or Symbols). obj[1] and obj['1'] access the same property. Use a Map if you need non-string keys.
How do I deeply clone an object?
Use structuredClone(obj) (available in Node 17+ and modern browsers). Alternatively, JSON.parse(JSON.stringify(obj)) works for plain data but drops functions, undefined, and Dates.
What does Object.fromEntries do?
It converts an iterable of [key, value] pairs into a plain object. It is the inverse of Object.entries() and is useful for transforming objects via array methods.
Ad – 336Γ—280

πŸ“‹ Summary

  • Object literals {} are the standard way to create objects in JavaScript.
  • Use dot notation for known keys; bracket notation for dynamic or special-character keys.
  • Methods defined with regular function syntax can use this to reference the object.
  • Object.keys/values/entries convert an object to iterable arrays.
  • Spread {...obj} creates a shallow copy; nested objects are still shared references.
  • Use shorthand properties and computed property names for cleaner ES6+ code.
  • in checks own and inherited properties; Object.hasOwn checks own only.
  • Object.freeze prevents all modifications; Object.seal prevents add/delete only.