Emmanuel Akinfulubi

Lesson 02 of 1511 min read

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.

A function becomes a method by living inside an object

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.

Three spellings, one meaning

// 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.

The method reads its own object

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.

The same job, done loosely

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.

Chaining, because each method hands the object back

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.

Property shorthand and computed keys

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


      

Destructuring: pulling properties out into variables

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.

keys, values, entries

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


      

See the problem for yourself

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.

Editable. Add the methods, then run it.

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, this is how you reach the rest of the object, which is what binds behaviour to data.
  • Return this from 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.

Saved in this browser only.

Newsletter

New writing, when it lands.

Occasional notes on shipping software with AI agents. No schedule, no filler, unsubscribe in one click.