# JavaScript Objects

Objects are the building blocks of real-world JavaScript. User profiles, API responses, settings, shopping carts: almost all of it is objects. This guide explains everything step by step: **what it is, how to use it, what it returns, and the gotchas**, with modern alternatives where they exist.

## Array vs Object: the quick difference

Both are containers, but they organize data differently.

|  | Array | Object |
| --- | --- | --- |
| Stores | Ordered list of values | Key-value pairs |
| Access by | Position: `arr[0]` | Name: `obj.name` |
| Best for | A list of similar things | One thing with many details |
| Size | `arr.length` | `Object.keys(obj).length` |
| Example | `["red", "green", "blue"]` | `{ name: "Sam", age: 20 }` |

```javascript
typeof [];            // "object" (arrays are objects too)
Array.isArray([]);    // true
Array.isArray({});    // false
```

![](https://cdn.hashnode.com/uploads/covers/69749e43424cff36234d3207/520f6302-70f5-4064-b1c0-f6d539a6d70c.png align="center")

## 1\. What is an object?

An object is a container that stores data as **key-value pairs**.

*   **Properties:** the data (variables inside the object).
    
*   **Methods:** the actions (functions inside the object).
    

```javascript
const user = {
  name: "Sam",            // property
  age: 20,                // property
  greet() {               // method
    return `Hi, I'm ${this.name}`;
  },
};
```

Keys are strings (or Symbols). Values can be anything: numbers, strings, arrays, other objects, functions.

## 2\. Creating objects

**Literal syntax (use this 99% of the time):**

```javascript
const empty = {};

const laptop = {
  brand: "Dell",
  ram: 16,
  specs: { storage: "512GB SSD" },      // nested object
  "serial number": "X123",              // key with a space needs quotes
};
```

**Constructor syntax (works, but longer):**

```javascript
const user = new Object();
user.firstName = "John";
user.age = 28;
```

Both give the same result. The literal is shorter and faster to read.

## 3\. Accessing properties

```javascript
const laptop = { 
  brand: "Dell", 
  ram: 16, 
  specs: { storage: "512GB" } 
};

laptop.brand;            // "Dell"       (dot notation)
laptop["ram"];           // 16           (bracket notation)
laptop.specs.storage;    // "512GB"      (nested)
laptop.color;            // undefined    (missing key, no error)
```

**When you need brackets:**

```javascript
const key = "brand";
laptop[key];                    // "Dell"  (key stored in a variable)
user["serial number"];          // key with a space or symbol
```

**Optional chaining** `?.` **prevents crashes** on missing nested data:

```javascript
laptop.gpu.name;        // TypeError: cannot read 'name' of undefined
laptop.gpu?.name;       // undefined (safe)
laptop.gpu?.name ?? "No GPU";   // "No GPU" (fallback)
```

## 4\. Adding, updating, and deleting

```javascript
const car = { brand: "Toyota" };

car.year = 2024;            // add
car["color"] = "red";       // add (bracket)
car.year = 2025;            // update
delete car.color;           // delete
```

**What** `delete` **returns:**

*   `true` if the property was removed **or never existed**.
    
*   `false` if it cannot be deleted (in strict mode it throws a `TypeError` instead).
    

**Rules:**

*   You can only delete an object's **own** properties, not ones inherited from its prototype.
    
*   Frozen or sealed objects (section 11) cannot lose properties.
    

**Gotcha:** `const` **does not freeze an object.** It only stops you from reassigning the variable.

```javascript
const car = { brand: "Toyota" };
car.brand = "Honda";     // allowed
car = {};                // TypeError: assignment to constant variable
```

## 5\. Methods and `this`

A method is a function stored as a property. Inside it, `this` points to the object.

```javascript
const user = {
  name: "Sam",
  greet() {                                // shorthand (recommended)
    return `Hi, I'm ${this.name}!`;
  },
};

user.greet();          // "Hi, I'm Sam!"
user["greet"]();       // "Hi, I'm Sam!"
```

The older style `greet: function () {}` works the same way. The shorthand just drops the word `function`.

**Gotcha: do not use arrow functions as methods.** Arrow functions have no `this` of their own.

```javascript
const user = {
  name: "Sam",
  greet: () => `Hi, ${this.name}`,   // `this` is NOT user
};
user.greet();   // "Hi, undefined"
```

## 6\. Getters and setters

A getter runs when you **read** a property. A setter runs when you **assign** to it. They look like normal properties from the outside.

```javascript
const person = {
  first: "Sam",
  last: "Lee",
  get fullName() {
    return `${this.first} ${this.last}`;
  },
  set fullName(value) {
    [this.first, this.last] = value.split(" ");
  },
};

person.fullName;              // "Sam Lee"   (no parentheses)
person.fullName = "Ana Kim";  // runs the setter
person.first;                 // "Ana"
```

## 7\. Property tricks

**Shorthand property names.** If the variable name equals the key, write it once.

```javascript
const a = "foo", b = 42;

const long = { a: a, b: b };
const short = { a, b };          // same result: { a: "foo", b: 42 }
```

**Computed property names.** Use `[ ]` to build a key from an expression.

```javascript
const field = "email";
const user = { [field]: "sam@mail.com", [`${field}Verified`]: true };
// { email: "sam@mail.com", emailVerified: true }
```

**Duplicate keys: the last one wins.**

```javascript
const a = { x: 1, x: 2 };
console.log(a);   // { x: 2 }
```

**Key order.** Whole-number keys come first in ascending order. Other keys follow in the order you added them.

```javascript
const o = { b: 1, 2: "two", a: 2, 1: "one" };
Object.keys(o);   // ["1", "2", "b", "a"]
```

## 8\. Checking if a property exists

```javascript
const user = { name: "Sam", age: undefined };

"name" in user;                    // true  (also checks inherited keys)
Object.hasOwn(user, "name");       // true  (own keys only, recommended)
user.age !== undefined;            // false (but the key exists!)
Object.hasOwn(user, "age");        // true
```

**Rule:** use `Object.hasOwn(obj, key)` to ask "does this key exist?". Checking `obj.key === undefined` cannot tell a missing key from a key whose value is `undefined`.

**Better than:** `obj.hasOwnProperty(key)`. `Object.hasOwn()` is shorter and also works on objects created with `Object.create(null)`.

## 9\. Looping through an object

```javascript
const spaceship = { name: "Apollo", speed: "28,000 km/h", fuel: "Liquid Hydrogen" };
```

### `for...in`

Gives each **key** as a string.

```javascript
for (const key in spaceship) {
  console.log(`${key}: ${spaceship[key]}`);
}
```

**Gotcha:** it also loops over **inherited** properties. If that matters, guard it:

```javascript
for (const key in spaceship) {
  if (Object.hasOwn(spaceship, key)) {
    console.log(key);
  }
}
```

### `Object.keys(obj)`

*   **Returns:** an array of the object's own keys.
    
*   Ignores inherited properties, so it is safer than `for...in`.
    

```javascript
Object.keys(spaceship);   // ["name", "speed", "fuel"]

Object.keys(spaceship).forEach((key) => {
  console.log(`${key}: ${spaceship[key]}`);
});
```

### `Object.values(obj)`

*   **Returns:** an array of the own values.
    

```javascript
Object.values(spaceship);   // ["Apollo", "28,000 km/h", "Liquid Hydrogen"]
```

### `Object.entries(obj)`

*   **Returns:** an array of `[key, value]` pairs. Best when you need both.
    

```javascript
const scores = { Player1: 950, Player2: 870, Player3: 1020 };

Object.entries(scores);
// [["Player1", 950], ["Player2", 870], ["Player3", 1020]]

for (const [player, score] of Object.entries(scores)) {
  console.log(`${player} scored ${score} points!`);
}
```

### `Object.fromEntries(pairs)`

The reverse of `entries`. Turns `[key, value]` pairs back into an object. Perfect for transforming objects.

```javascript
const doubled = Object.fromEntries(
  Object.entries(scores).map(([name, score]) => [name, score * 2])
);
// { Player1: 1900, Player2: 1740, Player3: 2040 }
```

**Which loop should I use?**

| You need | Use |
| --- | --- |
| Just the keys | `Object.keys()` |
| Just the values | `Object.values()` |
| Both key and value | `Object.entries()` with `for...of` |
| Build a new object | `Object.entries()` + `Object.fromEntries()` |
| Inherited keys too (rare) | `for...in` |

## 10\. Copying and merging objects

**Objects are copied by reference.** Assigning does not create a new object.

```javascript
const a = { x: 1 };
const b = a;       // same object, two names
b.x = 99;
console.log(a.x);  // 99

{} === {};         // false (two different objects)
```

**Shallow copy with spread (recommended):**

```javascript
const copy = { ...a };
const merged = { ...defaults, ...settings };   // later keys win
const updated = { ...user, age: 21 };          // copy and change one value
```

`Object.assign` does a similar job:

```javascript
Object.assign({}, a, b);   // copy into a new {} (the first argument is modified)
```

**Gotcha: both are shallow.** Nested objects are still shared.

```javascript
const original = { name: "Sam", address: { city: "Delhi" } };
const copy = { ...original };
copy.address.city = "Mumbai";
console.log(original.address.city);   // "Mumbai" (shared!)
```

**Deep copy with** `structuredClone`**:**

```javascript
const deep = structuredClone(original);
deep.address.city = "Pune";
console.log(original.address.city);   // unchanged
```

`structuredClone` cannot copy functions (it throws an error), so use it for plain data.

## 11\. Freezing and sealing

| Method | Add keys | Change values | Delete keys |
| --- | --- | --- | --- |
| `Object.freeze(obj)` | No | No | No |
| `Object.seal(obj)` | No | Yes | No |

```javascript
const config = Object.freeze({ mode: "dark" });
config.mode = "light";      // ignored (throws in strict mode)
config.mode;                // "dark"
Object.isFrozen(config);    // true
```

**Gotcha:** `freeze` is **shallow**. Nested objects can still change.

## 12\. Destructuring: pull out values quickly

```javascript
const user = { name: "Sam", age: 20, city: "Delhi" };

const { name, age } = user;                 // name = "Sam", age = 20
const { city: town } = user;                // rename: town = "Delhi"
const { country = "India" } = user;         // default value
```

Great for function parameters:

```javascript
function show({ name, age }) {
  return `${name} is ${age}`;
}
show(user);   // "Sam is 20"
```

## 13\. The `Object()` constructor

`Object(value)` turns any input into an object. It works the same with or without `new`.

| Input | Result |
| --- | --- |
| `null` or `undefined` | A new empty object `{}` |
| An object | The **same** object is returned |
| Anything else (number, string, ...) | A wrapper object of that type |

```javascript
Object();                    // {}
Object(null);                // {}
Object(user) === user;       // true

typeof Object(1);            // "object" (Number wrapper)
typeof Object("hi");         // "object" (String wrapper)
typeof Object(1n);           // "object" (BigInt wrapper)
typeof Object(Symbol("s"));  // "object" (Symbol wrapper)
```

**Gotcha:** `new BigInt()` and `new Symbol()` throw an error on purpose. This stops the common mistake of creating a wrapper instead of the real value. Calling `Object(...)` is the only way to make those wrappers.

```javascript
typeof new Number(1);   // "object" (wrapper, not a primitive)
typeof 1;               // "number"
```

Wrapper objects are rarely what you want. Use plain primitives.

## Optimized and modern choices

| Instead of | Use | Why |
| --- | --- | --- |
| `new Object()` | `{}` | Shorter, standard |
| `a: function () {}` | `a() {}` | Shorter method syntax |
| `{ a: a, b: b }` | `{ a, b }` | Shorthand |
| `obj.hasOwnProperty(k)` | `Object.hasOwn(obj, k)` | Safer and shorter |
| `a && a.b && a.b.c` | `a?.b?.c` | Optional chaining |
| `for...in` with a check | `Object.keys()` / `entries()` | No inherited keys |
| `Object.assign({}, a, b)` | `{ ...a, ...b }` | Cleaner |
| `JSON.parse(JSON.stringify(x))` | `structuredClone(x)` | Keeps dates, maps, and more |
| Arrow function as method | Method shorthand | Correct `this` |

## Quick reference: what each one returns

| Method | Returns |
| --- | --- |
| `obj.key` / `obj["key"]` | The value, or `undefined` |
| `delete obj.key` | `true` / `false` |
| `"key" in obj` | boolean (includes inherited) |
| `Object.hasOwn(obj, key)` | boolean (own only) |
| `Object.keys(obj)` | array of keys |
| `Object.values(obj)` | array of values |
| `Object.entries(obj)` | array of `[key, value]` |
| `Object.fromEntries(pairs)` | new object |
| `Object.assign(target, ...src)` | the modified `target` |
| `Object.freeze(obj)` / `Object.seal(obj)` | the same object, now locked |
| `structuredClone(obj)` | deep copy |

## Wrap up

*   Objects store **key-value pairs**: properties for data, methods for actions.
    
*   Use **literals**, **dot notation** for fixed keys, and **brackets** for dynamic ones.
    
*   Loop with `Object.keys()`, `values()`, or `entries()`, not raw `for...in`.
    
*   Remember objects are copied **by reference**. Use spread for a shallow copy and `structuredClone` for a deep one.
    
*   `const` does not make an object immutable. Use `Object.freeze()` for that.
    

Try each example in your browser console. Seeing the return values yourself is the fastest way to make them stick.
