2

I am defining an object where I want to calculate one of it's properties with another of it's properties.

// first the calculation function
const calculateArea = (height, width) => {
   return height * width
}

// then the object itself...
const myObj = {
   height: 20,
   width: 10,
   area: calculateArea(this.height, this.width)
}

I thought I could use this.height and this.width to access properties within the object I was defining, but I get

Cannot read 'height' of undefined

Where am I going wrong, and what's the solution?

Paulos3000
  • 3,355
  • 10
  • 35
  • 68

2 Answers2

1

The problem is, you are trying to reference to your object with this, while it doesn't exist. The this you reference may be undefined (as in your case), which then results in a "cannot read X property of undefined" error.

However the this might be bound to another object in the context depending on the situation. In that case you wouldn't get this error and whatever the value corresponds to the bound object's will be returned as this.

Trying to fetch a value from the retrieved this object may result in 2 cases, both of which are not the thing you want.

  • The retrieved this has a width and a height property, so that your function will get these values and calculate the result accordingly. But these values will not be the ones that you passed in your object.

  • The retrieved this doesn't have a width or height property, so that your function will get undefined as it's parameters and will throw an error accordingly.

There are many ways you can solve this issue. Here is my proposition:

The main issue here is that the value for area is calculated eagerly while you are constructing your object. Freezing that calculation and triggering it after the object is created will calculate the correct value within your object.

// first the calculation function
const calculateArea = (height, width) => {
   return height * width
}

// then the object itself...
const myObj = {
    height: 20,
    width: 10,
    // init, is a function that uses bounded context's width, height
    init: function() {
        this.area = calculateArea(this.height, this.width);
        delete this.init; // We don't want init in our result object
        return this;
    }
}.init();

Now when we call init() of our object, we will have our this pointing to the correct object. It will calculate the area with this.width and this.height. It will also delete the init() function from the result object and return the object as in the form you wanted.

We just halted the calculation for a step to have our this to point to correct context and then continued.

Let Me Tink About It
  • 15,156
  • 21
  • 98
  • 207
0
function myObj(height, width) {
  this.height = height;
  this.width = width;
  this.area = calculateArea(height, width);
}

let obj = new myObj(20, 10);
Let Me Tink About It
  • 15,156
  • 21
  • 98
  • 207
  • 1
    While this code may answer the question, it would be better to explain how it solves the problem without introducing others and why to use it. Code-only answers are not useful in the long run. – Al Foиce ѫ Sep 12 '19 at 20:12
  • The provided answer was flagged for review as a Low Quality Post. Here are some guidelines for [How do I write a good answer?](https://stackoverflow.com/help/how-to-answer). This provided answer may be correct, but it could benefit from an explanation. – Trenton McKinney Sep 13 '19 at 04:10