Javascript – Property of a Javascript Class calculated from other properties in same Class

classjavascriptproperties

This is probably something pretty silly that I'm missing but how do I get the property of a class to automatically re-calculate based on the values of other properties in the same class?

e.g.

function Test() {
    this.prop1 = 1;
    this.prop2 = 2;
    this.prop3 = this.prop1 + this.prop2;

}

tester = new Test();

alert (tester.prop1); // expect 1
alert (tester.prop2); // expect 2
alert (tester.prop3); // expect 3

tester.prop1 += 1;

alert (tester.prop1); // expect 2
alert (tester.prop2); // expect 2
alert (tester.prop3); // expect 4

or do I need to have prop3 set to be = calcProp3() and then include a function like so:

this.calcProp3 = function() {
        var calc = this.prop1 + this.prop2;
        return calc;
    }

Thanks all.

Best Solution

or do I need to have prop3 set to be = calcProp3() and then include a function

You have two choices:

  1. Create a property with a getter, which looks like a simple property access when you use it, but is in fact calling a function, or

  2. Do your calcProp3 function, which makes it apparent to the coder using Test that they're calling a function

Option 2 is your only option if you need to support truly obsolete browsers like IE8, since IE8 doesn't support getters.

Using a getter

Here in 2017 you'd probably define it in a class (transpiling if necessary for browsers that don't support ES2015's [aka "ES6"] class):

class Test {
  constructor() {
    this.prop1 = 1;
    this.prop2 = 2;
  }
  get prop3() {
    return this.prop1 + this.prop2;
  }
}
const t = new Test();
console.log(t.prop3); // 3
t.prop1 = 2;
console.log(t.prop3); // 4

If you wanted to limit yourself to features of ES5 (spec released December 2009, not supported in IE8), you'd define a getter on Test.prototype, either by using Object.defineProperty (spec, MDN):

function Test() {
  this.prop1 = 1;
  this.prop2 = 2;
}
Object.defineProperty(Test.prototype, "prop3", {
  get: function() {
    return this.prop1 + this.prop2;
  }
});
var t = new Test();
console.log(t.prop3); // 3
t.prop1 = 2;
console.log(t.prop3); // 4

...or by replacing Test.prototype and using the object initializer syntax for getters (remember to set constructor):

function Test() {
  this.prop1 = 1;
  this.prop2 = 2;
}
Test.prototype = {
  constructor: Test,
  get prop3() {
    return this.prop1 + this.prop2;
  }
};
var t = new Test();
console.log(t.prop3); // 3
t.prop1 = 2;
console.log(t.prop3); // 4

Using a function

Here in 2017, you'd probably define it as a method using class syntax (transpiling if necessary for older browsers):

class Test {
  constructor() {
    this.prop1 = 1;
    this.prop2 = 2;
  }
  calcProp3() {
    return this.prop1 + this.prop2;
  }
}
const t = new Test();
console.log(t.calcProp3()); // 3
t.prop1 = 2;
console.log(t.calcProp3()); // 4

If you wanted to stick with ES5 (actually in this case ES3) features to support obsolete browsers, just add a function to the prototype:

function Test() {
  this.prop1 = 1;
  this.prop2 = 2;
}
Test.prototype.calcProp3 = function calcProp3() {
  return this.prop1 + this.prop2;
};
var t = new Test();
console.log(t.calcProp3()); // 3
t.prop1 = 2;
console.log(t.calcProp3()); // 4