LEARN TO CODE | JAVASCRIPT | 02 FUNCTIONS AND COLLECTIONS
02.3 Objects and properties
Represent a record with named properties, process an array of objects and recognise when two names refer to the same mutable data.
01 | ONE CLUB HAS SEVERAL RELATED FACTS
A club has a name, a room and a capacity. Keeping those facts in unrelated variables becomes awkward once you have several clubs. You want each club’s details to stay together.
An object groups named properties. Each property associates a key with a value. An object representing one club is like a record with labelled fields.
An array is useful for an ordered collection of clubs; an object is useful for the related details of one club. They work together rather than replacing each other.
Keep index.html and script.js in the same VS Code folder. Put the current example into script.js, save it, open or refresh index.html in your browser and look in that page’s Developer Tools Console.
Replace the previous example unless a task explicitly says to add to it. Pasting several independent examples together can redeclare the same let or const name. The downloadable examples use a separate folder for each complete program.
02 | CREATE AN OBJECT LITERAL
const club = {
name: "Robotics",
room: "B12",
capacity: 12,
isOpen: true
};
console.log(club.name);
console.log(club.capacity);
Curly braces surround the object literal. A colon separates a property key from its value, and commas separate properties. The property name name labels the string "Robotics"; capacity labels the number 12.
This is different from an assignment statement such as const capacity = 12. Inside this object literal, key: value describes a property. The entire object is then assigned to club.
Objects can contain strings, numbers, booleans, arrays, other objects and functions. For now, choose a small set of predictable properties for each record.
03 | READ WITH DOT OR BRACKET NOTATION
const club = { name: "Robotics", capacity: 12 };
console.log(club.name);
console.log(club["name"]);
const field = "capacity";
console.log(club[field]);
club.name reads the property literally named name. club["name"] reads the same property using a string key.
club[field] first reads the variable field, giving "capacity", then reads that property. club.field would instead ask for a property actually named field, which this object does not have.
Bracket notation is also needed for keys that cannot be written as simple identifiers, such as "meeting day". For your own beginner data, straightforward camelCase keys usually make code easier to read.
TRY IT YOURSELF
If field contains "name", what is club[field]? What is club.field in this example?
Reveal guidance
club[field] is "Robotics". club.field is undefined because there is no property named field.
04 | UPDATE AND ADD PROPERTIES
const club = { name: "Robotics", capacity: 12 };
club.capacity = 14;
club.meetingDay = "Tuesday";
console.log(club.capacity);
console.log(club.meetingDay);
Assigning to an existing property updates its value. Assigning to a new property adds it to this ordinary object. const keeps club bound to the same object but does not prevent property changes.
A misspelling can therefore quietly add the wrong property. club.capcity = 14 does not update capacity. Inspect the object keys and keep a consistent record shape.
These updates live in the page’s current memory. They are not saved to a database or file, and reloading the page reruns the source data.
05 | MISSING IS NOT THE SAME AS ZERO
const club = { name: "Robotics", placesLeft: 0 };
console.log(club.placesLeft);
console.log(club.teacher);
console.log(Object.hasOwn(club, "placesLeft"));
console.log(Object.hasOwn(club, "teacher"));
Zero places left is valid data meaning the club is full. A missing teacher property returns undefined. A truthiness check such as if (club.placesLeft) would not distinguish zero from an absent value in the way you might intend.
Object.hasOwn checks whether the object has that own property. That is different from checking whether its value is truthy; a present property can even deliberately hold undefined.
For unknown external records, validate the expected properties before calculating with them. An object’s existence alone does not prove that it has the shape your program needs.
06 | A METHOD IS A FUNCTION PROPERTY
const club = {
name: "Robotics",
capacity: 12,
describe() {
return `${this.name}: ${this.capacity} places`;
}
};
console.log(club.describe());
describe is a method. In the direct call club.describe(), this refers to club, so this.name reads that object’s name property.
This explanation applies to this ordinary method call. this is not a general synonym for “the object nearest in the source”: its behaviour depends on how a function is called. An arrow function also does not create its own this binding.
For now, call this method through club.describe(). Do not extract it into an unrelated variable or convert it to an arrow and expect identical this behaviour. A separate function accepting club as a parameter is another clear option.
07 | AN ARRAY OF OBJECTS IS A SMALL DATASET
const clubs = [
{ id: 1, name: "Robotics", capacity: 12 },
{ id: 2, name: "Art", capacity: 8 },
{ id: 3, name: "Coding", capacity: 16 }
];
console.log(clubs[0].name);
for (const club of clubs) {
console.log(`${club.name}: ${club.capacity}`);
}
Read clubs[0].name in two stages: access the object at array index 0, then access that object’s name property. The loop’s club parameter-like iteration binding refers to one object on each pass.
id is a property we chose to identify a record. It is not the same as an array index. Reordering the array can change an object’s index while its id stays the same.
08 | ASK QUESTIONS ABOUT YOUR RECORDS
const clubs = [
{ id: 1, name: "Robotics", capacity: 12 },
{ id: 2, name: "Art", capacity: 8 },
{ id: 3, name: "Coding", capacity: 16 }
];
const largeClubs = clubs.filter((club) => club.capacity >= 12);
const names = largeClubs.map((club) => club.name);
console.log(names.join(", "));
const chosen = clubs.find((club) => club.id === 2);
if (chosen !== undefined) {
console.log(chosen.name);
}
filter selects object references that meet the rule; map turns those selected objects into name strings. find searches for one ID and the code checks for a missing result before reading its name.
These are data operations, not page rendering yet. Later lessons will use the same collection to produce visible webpage elements.
09 | TWO NAMES CAN REFER TO ONE OBJECT
const original = { name: "Robotics", capacity: 12 };
const alias = original;
alias.capacity = 20;
console.log(original.capacity);
console.log(alias === original);
Assigning original to alias does not create a second independent object. Both bindings refer to the same object. Updating it through either name is visible through the other.
JavaScript passes argument values by value. When that value is an object reference, a function receives a copy of the reference and can therefore mutate the shared object. Reassigning the parameter itself is a different operation.
function changeCapacity(record) {
record.capacity = 18;
record = { capacity: 99 };
}
const club = { capacity: 12 };
changeCapacity(club);
console.log(club.capacity);
The property mutation changes the original object to 18. The later parameter reassignment changes only the function’s local binding; it does not replace the caller’s club binding.
10 | COPIES ARE OFTEN SHALLOW
const original = {
name: "Robotics",
details: { room: "B12" }
};
const copy = { ...original };
copy.name = "Coding";
copy.details.room = "C10";
console.log(original.name);
console.log(original.details.room);
The spread syntax copies these own enumerable properties into a new outer object. Changing copy.name does not change original.name. But details still refers to the same nested object, so changing its room affects both views.
Likewise, slice and filter create new arrays but keep references to the same selected objects. “New array” does not mean “deeply independent dataset”. Design a deliberate copying strategy when nested independence is required.
11 | READ KEYS AND BUILD A REPORT
const club = { name: "Robotics", capacity: 12 };
for (const key of Object.keys(club)) {
console.log(`${key}: ${club[key]}`);
}
Object.keys returns an array of this object’s own enumerable string keys. The loop uses each key with bracket notation to read its value.
TRY IT YOURSELF
Create two club records with id, name and capacity. Write a function that accepts the array and returns the names of clubs with capacity at least 10, as an array of strings.
Reveal guidance
function namesForLargeClubs(clubs) {
return clubs
.filter((club) => club.capacity >= 10)
.map((club) => club.name);
}
const clubs = [
{ id: 1, name: "Robotics", capacity: 12 },
{ id: 2, name: "Art", capacity: 8 }
];
console.log(namesForLargeClubs(clubs).join(", "));
KEEP LEARNING
Previous page 02.4 Scope and debugging
Download Section 02 example programs
Further reading: Functions · Arrays · Objects · VS Code browser debugging