Если вы хотите, чтобы ссылки были общедоступными, чтобы можно было вызвать bob.barker.bark(), тогда MurderRobotDog будет выглядеть так:

class MurderRobotDog {
 constructor(barker, killer, driver) {
  this.barker = barker;
  this.killer = killer;
  this.driver = driver;
 }
}

Или, наоборот, ссылки могут быть закрытыми, и MurderRobotDog может реализовать свой собственный интерфейс:

class MurderRobotDog {
 constructor(barker, killer, driver) {
  this._barker = barker;
  this._killer = killer;
  this._driver = driver;
 }
 bark() {
  return this._barker.bark();
 }
 kill() {
  return this._killer.kill();
 }
 drive() {
  return this._driver.drive();
 }
}

Если это выглядит немного избыточным или странным, то это потому, что этот конкретный пример на самом деле является идеальным вариантом использования наследования. Поддерживайте композицию, но не позволяйте этому отговорить вас от использования наследования, когда это правильный инструмент для работы.

Если, с другой стороны, MurderRobotDog захотел использовать свои приватные ссылки для реализации совсем другого интерфейса, тогда композиция стала бы выглядеть намного лучше:

class MurderRobotDog {
 constructor(barker, killer, driver) {
  this._barker = barker;
  this._killer = killer;
  this._driver = driver;
 }
 killAndFlee() {
  this._killer.kill();
  this._driver.drive();
  this._barker.bark();
 }
}