Free lesson · JavaScript Basic to Advance
Objects: The Foundation
What Is an Object?
An object in JavaScript is a collection of key-value pairs. The keys are strings (or symbols, occasionally). The values can be anything — numbers, strings, booleans, other objects, arrays, functions. Objects are the primary way JavaScript represents structured data.
const user = {
name: "Olena",
age: 35,
role: "Head of Product",
isActive: true,
greet: function() {
return `Hi, I'm ${this.name}`;
}
};
console.log(user.name);
console.log(user.age);
console.log(user.greet());
That's an object. Five properties, each with its own key and value. One of the values happens to be a function — that's a method. From a JavaScript perspective, methods are just properties whose values happen to be functions.
I'm Nikhil. Module 7 is all about objects — what they are, how to work with them, and the prototype mechanism that makes JavaScript's object model different from most other languages. By the end of this module, you should be able to read any JavaScript codebase that deals with object structures and understand exactly what's happening.
Why Objects Matter So Much in JavaScript
JavaScript is sometimes described as "everything is an object." That's slightly exaggerated — primitives like numbers, strings, and booleans aren't objects. But almost everything else is. Arrays are objects. Functions are objects. Dates are objects. Errors are objects. Even the Math and JSON globals you use are objects.
This matters because once you understand how objects work, you understand how most of JavaScript is structured. Arrays are just objects with numeric keys and special methods. Functions are objects you can call. Classes (Module 8) are syntactic sugar over object creation patterns. The DOM is a tree of objects.
Closures (Module 6) gave you the runtime model — execution contexts and scope chains. Objects give you the data model. Together they're the foundation everything else in JavaScript is built on.
Interactive animation: The honest census - plain objects, arrays and functions are objects, while primitives are not.
Creating Objects
JavaScript gives you several ways to create objects. The most common is object literal syntax — curly braces with key-value pairs:
const empty = {};
const point = { x: 3, y: 4 };
const user = {
name: "Olena",
age: 35,
preferences: {
theme: "dark",
notifications: true
}
};
console.log(empty);
console.log(point);
console.log(user);
console.log(user.preferences.theme);
Object literals can be nested — values can themselves be objects, which can contain other objects. This is how complex structured data gets represented.
Keys can be any string. If a key isn't a valid identifier (like contains spaces or starts with a number), you wrap it in quotes:
const weirdKeys = {
name: "Olena",
"first name": "Olena",
"user-id": 42,
"2023-data": "old"
};
console.log(weirdKeys.name); // dot notation works for normal keys
console.log(weirdKeys["first name"]); // bracket notation for special keys
console.log(weirdKeys["user-id"]);
We'll cover the dot vs bracket access distinction in detail in the next Topic.
Computed Keys
You can compute a key dynamically using square brackets in the literal itself:
const keyName = "dynamic";
const obj = {
[keyName]: "value",
[`${keyName}_extended`]: "another value",
[1 + 2]: "three"
};
console.log(obj);
console.log(obj.dynamic);
console.log(obj.dynamic_extended);
console.log(obj[3]);
The expression inside [...] is evaluated, and the result becomes the key. This is useful when keys come from variables or are derived from other data. Note that the last one — [1 + 2] — produces the key "3" as a string, because object keys are always strings (or symbols).
Interactive animation: [expression] as a property name - the brackets run the expression and the result becomes the key.
Interactive animation: Every key becomes a string - so two different objects used as keys collide on one key.
Property Shorthand
When you're creating an object where a key has the same name as a variable holding its value, you can use shorthand syntax:
const name = "Olena";
const age = 35;
const role = "Head of Product";
// Old way (verbose)
const userVerbose = {
name: name,
age: age,
role: role
};
// Shorthand
const user = { name, age, role };
console.log(userVerbose);
console.log(user);
Both objects are identical. The shorthand version is just cleaner. This pattern shows up constantly in modern JavaScript, especially when returning objects from functions:
function makeUser(name, age) {
const role = "member";
const createdAt = Date.now();
return { name, age, role, createdAt };
}
console.log(makeUser("Olena", 35));
The function returns an object whose keys come from the local variable names. No name: name repetition needed.
Symbol Keys (Brief Mention)
In addition to string keys, objects can have symbol keys. Symbols are unique values that can be used as keys to avoid collisions with regular string keys.
const id = Symbol("id");
const obj = {
name: "Olena",
[id]: 12345
};
console.log(obj.name);
console.log(obj[id]);
console.log(Object.keys(obj)); // ['name'] — symbol keys don't appear here
Symbol keys are useful for adding metadata to objects without risking collision with normal keys, and for some advanced patterns (like making objects iterable, which we touch on in Module 10). For day-to-day code, you'll rarely use them directly.
Objects Are Reference Types
This is the single most important property of objects to understand: objects are passed and assigned by reference, not by value.
const a = { count: 0 };
const b = a;
b.count = 5;
console.log(a.count); // 5 — a and b point to the SAME object
const c = a;
c.count = 100;
console.log(a.count); // 100 — c also points to the same object
console.log(b.count); // 100 — and so does b
When you write const b = a, you're not copying the object. You're copying the reference to the object. Both a and b now point to the same object in memory. Modifying it through b is visible through a, because they're the same thing.
This is different from primitives:
let x = 5;
let y = x;
y = 10;
console.log(x); // 5 — primitives are copied by value
Primitives (numbers, strings, booleans, etc.) are copied. Objects (and arrays, and functions) are referenced.
graph TD
A[const obj = ...] --> B[Memory: object data]
C[const ref = obj] --> B
D[const another = obj] --> B
E[let x = 5] --> F[Memory: 5]
G[let y = x] --> H[Memory: 5 separate copy]
style B fill:#7c3aed,color:#fff
style F fill:#10b981,color:#fff
style H fill:#10b981,color:#fff
This diagram shows the difference between reference types and value types in JavaScript. When you assign an object to multiple variables, all of those variables point to the same memory location — they all reference the same object. Modifying the object through any one of those variables affects what all of them see. When you assign a primitive value like a number to multiple variables, each variable holds its own copy of the value. Modifying one doesn't affect the others.
This has practical consequences. Functions that receive objects as arguments can modify them, and the caller will see the changes. Comparing objects with === compares references, not contents. We'll see all of this play out throughout this module.
Comparing Objects
Two objects with identical contents are not equal to each other:
const a = { name: "Olena" };
const b = { name: "Olena" };
const c = a;
console.log(a === b); // false — different objects in memory
console.log(a === c); // true — same object, two references
=== on objects compares references. Two separately-created objects, even with identical contents, are different references. The same object accessed through different variables is the same reference.
To compare object contents, you need to compare property-by-property — either manually, or with a deep-equality utility from a library, or with JSON.stringify (which has its own limitations covered in Module 2).
Interactive animation: One object, two names - an edit through either shows in both, and identical contents still compare false.
Common Pitfalls
Warning: The object basics traps.
Assuming
=copies an object. It doesn't — it copies the reference. To actually copy an object's contents, use the spread operator{ ...source }(covered in Module 10) or a deep-copy utility.Trying to use
===to compare object contents. That compares references, not values.{a: 1} === {a: 1}isfalse. To compare contents, you have to compare property-by-property.Mutating object arguments inside a function. Because objects pass by reference, modifying an argument inside a function affects the caller's version. Sometimes this is intentional; often it's an accidental side effect. Be deliberate about whether you're mutating arguments.
Why This Matters in Interviews
Interview: "What's the difference between value types and reference types in JavaScript?" is a common warm-up question. The expected answer: primitives are copied by value, objects (including arrays and functions) are copied by reference. Mention that
===on objects compares references, not contents.Topic 7.8 — Interview Lens: Objects and Prototypes — covers the deeper interview-prep treatment, including the puzzles that test whether you understand reference semantics.
Try It
Exercise: Predict the output of this code, then run it:
const obj1 = { count: 0 }; const obj2 = obj1; const obj3 = { count: 0 }; obj2.count = 5; console.log(obj1.count); console.log(obj2.count); console.log(obj3.count); console.log(obj1 === obj2); console.log(obj1 === obj3);Why does modifying
obj2.countaffectobj1.countbut notobj3.count? Why doesobj1 === obj2returntruewhileobj1 === obj3returnsfalse?Once you can explain this without hesitation, you've internalized the reference model. Everything in the rest of Module 7 builds on this.