Properties and Methods
A property is something an object knows. A method is something an object can do. Once a function lives inside an object, it gains a superpower: it can see the rest of the object.
By the end: Give an object behaviour, not just data.
So far your objects have only known things. Now they will start to do things.
A function stored as a property is called a method. That is the whole definition. There is no separate method keyword and nothing special about the function itself.
const horn = {
name: 'bus horn',
sound() {
console.log('beep');
},
};
horn.sound();
console.log(typeof horn.sound);
Output
Three ways to write the same thing. The first is modern shorthand and the one you should use.
// Shorthand method. Use this.
const a = {
sound() { console.log('beep'); },
};
// A function expression assigned to a property. Identical behaviour.
const b = {
sound: function () { console.log('beep'); },
};
// An arrow function. Looks the same, behaves differently. Lesson 03 explains why.
const c = {
sound: () => { console.log('beep'); },
};
Why putting the function inside matters
Here is the payoff. A method can reach the object it was called on, using the keyword this. So the behaviour and the data it needs sit in one place, and you stop passing the same values around.
const bus = {
plate: 'LAG-441-XA',
seatsLeft: 9,
hasBookings: false,
describe() {
return this.plate + ' has ' + this.seatsLeft + ' seats left';
},
book(n) {
this.seatsLeft = this.seatsLeft - n;
this.hasBookings = true;
},
};
console.log(bus.describe());
bus.book(3);
console.log(bus.describe());
console.log('Any bookings?', bus.hasBookings);
Output
Compare that with the alternative. Without methods, every function needs the data handed to it, and nothing stops you handing it the wrong thing.
function describe(plate, seatsLeft) {
return plate + ' has ' + seatsLeft + ' seats left';
}
// Nothing here prevents this:
describe(9, 'LAG-441-XA'); // "9 has LAG-441-XA seats left"
Returning this, so calls can chain
If a method has nothing useful to return, return this. The caller gets the object back and can immediately call another method on it. This is called a fluent interface, and it is how libraries like jQuery and query builders read the way they do.
const boarding = {
passengers: [],
add(who) {
this.passengers.push(who);
return this;
},
close() {
this.closed = true;
return this;
},
report() {
console.log(this.passengers.length, 'on board, doors closed:', Boolean(this.closed));
return this;
},
};
boarding.add('Amaka').add('Chidi').add('Bola').close().report();
Output
Shorthand you will read everywhere
Two conveniences worth knowing now, because other people's code is full of them.
const plate = 'ENU-318-PH';
const seatsLeft = 11;
// When the key and the variable share a name, write it once.
const bus = { plate, seatsLeft };
console.log(bus);
// A key computed at build time goes in square brackets.
const field = 'registeredIn';
const record = { [field]: 2018, ['is' + 'Ready']: true };
console.log(record);
Output
const bus = { plate: 'ABJ-772-KM', seatsLeft: 6, ready: false };
const { plate, seatsLeft } = bus;
console.log(plate, seatsLeft);
// Rename on the way out, and supply a default for a missing key.
const { plate: which, owner = 'unknown' } = bus;
console.log(which, 'owned by', owner);
// Works in a parameter list too, which is very common.
function label({ plate, seatsLeft }) {
return plate + ' (' + seatsLeft + ')';
}
console.log(label(bus));
Output
Walking every property
Three tools, and one of them is almost always the right one.
const bus = { plate: 'LAG-441-XA', seatsLeft: 9, ready: true };
console.log(Object.keys(bus));
console.log(Object.values(bus));
console.log(Object.entries(bus));
// entries plus destructuring is the readable way to loop an object.
for (const [key, value] of Object.entries(bus)) {
console.log(key, '=', value);
}
Output
const bus = {
plate: 'LAG-441-XA',
seatsLeft: 9,
describe() { return this.plate; },
};
console.log(Object.keys(bus));
Output
Your turn: give it behaviour
The counter below only holds data. Add two methods: tick() which raises count by one and returns this, and report() which logs the label and the count. Then chain three ticks and a report in one line.
Output
Recap
- A method is nothing more than a function stored as a property.
- Use the shorthand form
name() { }inside object literals. - Inside a method,
thisis how you reach the rest of the object, which is what binds behaviour to data. - Return
thisfrom a method with no other useful return value, and calls will chain. Object.entries()with destructuring is the clearest way to loop over an object's own properties.