1

I’m transforming data I receive from an API. The frontend requires some calculations to be displayed.

What is the proper way to handle the data transformation?

  • Should I be defining a property to the object being passed? If so, why
  • Is this a good use case to use setters and getters or would that be unnecessary?

const dogData = {
  dog_name: "filo",
  born_time: 1530983852,
  coat_color: "brown"
};

class Dog {
  constructor(data) {
    //do I need to set this.dog to the data object, what's the benefit of doing so?
    this.dog = data;

    this.name = this.dog.dog_name;
    // vs
    this.name = data.dog_name;

    //Should I use setters and getters?
    this.color = this.dog.coat_color;
    // vs
    this._color = this.dog.coat_color;

    this.age = this.calculateAge();
  }

  calculateAge() {
    return Date.now().getTime() - this.dog.born_time;
  }

  //Is this a good case where I  should using getters to access the properties or would that be superfluous?
  //should I be setting the properties with setters in this case?
  get color() {
    return this._color;
  }
}

const dog = new Dog(dogData)
12
  • Dog.dog doesn't make sense. Just set the properties of the Dog (name & colour) and have the function for returning the age. Anything else is overkill, unless you can think of a reason to add them. Commented Dec 13, 2018 at 17:40
  • I don't have control over the shape of the data I'm receiving. This class is meant to make the data easier to consume by a react application. Commented Dec 13, 2018 at 17:43
  • Will Dog instances be immutable or will you allow properties like born_time to be changed after construction? Commented Dec 13, 2018 at 17:51
  • I can't think of a time I may need to mutate it. Commented Dec 13, 2018 at 17:57
  • If the OP never needs to mutate the initial configuration then an approach needs to work with getter functionality assigned/bound from within the constructor. There also is no need of any prototypal methods. But there should be exactly one local function that calculates the age for each Dog instance. Commented Dec 13, 2018 at 18:26

3 Answers 3

2

Your don't need to make a copy of data into your class.

You can assign the class fields directly (using object destructuring to be more readable).

const data = {
  dog_name: 'filo',
  born_time: 1530983852,
  coat_color: 'brown'
}

class Dog {
  // Directly assign values
  constructor({ dog_name, born_time, coat_color }) {
    this.name = dog_name
    this.bornAt = born_time
    this.color = coat_color
  }

  // Getter for computed properties
  get age() {
    return Date.now() - this.bornAt
  }
}

const dog = new Dog(data)

Getters are needed only for computed property (dynamic or formatted values).

Good exemple:

class Person {
  constructor({ firstname, lastname }) {
    this.firstname = firstname
    this.lastname = lastname
  }

  get fullname() {
    return `${this.firstname} ${this.lastname}`
  }
}
Sign up to request clarification or add additional context in comments.

6 Comments

Updated, hope it helps. Thanks
Would it be wrong to have a function getFullName with a property defined in the constructor this.fullName = this.getFullName(firstName, lastName)?
Also, if there are many properties, 10+, is it still worth it to destructure?
It would not be wrong, but no need to define a function getFullName You could just do this.fullname = firstname + ' ' + lastname. Defining a function for a one-time usage into the constructor seems not very clean. If there are many properties, always target the best readability.
Readability prevails regardless of the number of properties, if destructuring decreases readability it is not worth it, prefer this.prop = data.prop.
|
0

class Dog {
    constructor(data) {
        const {
            dog_name: name,
            born_time: age,
            coat_color: color
        } = data;
        Object.assign(this, {
            name,
            age,
            color
        });
    }
}

const dogData = {
    dog_name: "filo",
    born_time: 1530983852,
    coat_color: "brown"
};

const dog = new Dog(dogData);

console.log(dog.name);

1 Comment

born_time is fixed but age does vary over time, at least according to the OP's example.
0

Q:

Shall I nevertheless throw in a possible read only approach? – Peter Seliger

A:

It wouldn't hurt. I appreciate the different approaches. – Matthew Moran

... here we go ...

// module start ... e.g. file: "Dog.js"


// locally scoped helper function
function calculateAge(dateOfBirth) {
  return (Date.now() - dateOfBirth);
}

/*export default */class Dog {
  constructor(initialValue) {

    Object.defineProperties(this, {
      valueOf: { // just in order to hint what `initialValue` might still be good for.
        value: function () {
          return Object.assign({}, initialValue);
        }
      },
      name: {
        value: initialValue.dog_name,
        enumerable: true
      },
      color: {
        value: initialValue.coat_color,
        enumerable: true
      },
      age: {
        get() {
          return calculateAge(initialValue.born_time);
        },
        enumerable: true,
      }
    });
  }
}
// module end.


// test
const dogData = {
  dog_name: "filo",
  born_time: 1530983852,
  coat_color: "brown"
};

const dog = new Dog(dogData);

console.log('Object.keys(dog) : ', Object.keys(dog));
console.log('dog.valueOf() : ', dog.valueOf());

console.log('dog.age : ', dog.age);
console.log('dog.name : ', dog.name);
console.log('dog.color : ', dog.color);

console.log('(dog.age = 298146912) : ', (dog.age = 298146912) && dog.age);
console.log('(dog.name = "spot") : ', (dog.name = "spot") && dog.name);
console.log('(dog.color = "black") : ', (dog.color = "black") && dog.color);
.as-console-wrapper { max-height: 100%!important; top: 0; }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.