1

Can you help me achieve the expected coding?

Actual Code

  let garage = new Garage();

  // getter outputs array of car objects
  garage.cars

  // independent method outputs array of car brands
  garage.carsBrands();

Expected Code

  let garage = new Garage();

  // getter outputs array of car objects
  garage.cars

  // method chained to former getter outputs array of car brands
  garage.cars.brands();

brands() uses cars output value to return its own value.

jurordrained
  • 131
  • 2
  • 9
  • you can extend it but its not intuitive. look up the law of demeter. – Daniel A. White Aug 29 '20 at 19:16
  • Rather than being an array of `Car` objects, `cars` would itself have to be a custom object representing a collection of `Car` objects, that implements `brands()`. – jarmod Aug 29 '20 at 19:16
  • https://stackoverflow.com/questions/11421986/add-a-method-to-array-object-in-javascript – kmoser Aug 29 '20 at 19:19
  • 1
    Can you guys give me an example? – jurordrained Aug 29 '20 at 19:20
  • It can’t be both an array and a custom non-array type, and the alternatives that would make that exact syntax work (extend all arrays, attach methods directly to the array, create a custom type that inherits from `Array`) are bad. I would recommend a function `brands` that can be called with `brands(garage.cars)`. – Ry- Aug 29 '20 at 19:22
  • Your first example makes more sense. You don't want a brands method on the array. – Adrian Brand Aug 29 '20 at 19:48

1 Answers1

1

You would need to extend the array of cars with an extra method.

Note however, that this is not really considered best practice, as users of your code would expect arrays to be plain arrays -- nothing more, nothing less.

Anyway:

class Garage {
    constructor() {
       this._cars = Object.assign([], { brands: () => this.carsBrands() });
    } 
    addCar(brand, year) {
       this._cars.push({brand, year});
       return this;
    }
    get cars() {
        return this._cars;
    }
    carsBrands() {
        return [...new Set(this._cars.map(car => car.brand))]; // make unique
    }
}

let garage = new Garage();
garage.addCar("Toyota", 2007).addCar("BMW", 2019);

console.log(garage.cars);
console.log(garage.cars.brands());

A more acceptable design could be to let cars be a plain object with a few different methods, among which a method to get the array of objects, and one to get the array of brand names.

For example:

class Garage {
    constructor() {
       this.cars = {
          entries: [],
          get brands() {
              return [...new Set(this.entries.map(car => car.brand))];
          } 
       };
    } 
    addCar(brand, year) {
       this.cars.entries.push({brand, year});
       return this;
    }
}

let garage = new Garage();
garage.addCar("Toyota", 2007).addCar("BMW", 2019);

console.log(garage.cars.entries);
console.log(garage.cars.brands);
trincot
  • 317,000
  • 35
  • 244
  • 286