JRulle
JRulle

Reputation: 7568

Javascript Object Properties Calculated (on the fly) from Other Object Properties

I am trying to create a javascript object that calculates various values for the properties set on it. I have compiled this simple example of what I am trying to achieve: JSFIDDLE

var obj = {};
obj.a = 2;
obj.b = 5;
obj.avg = "(obj.a + obj.b)/2"; 
obj.rounded = "Math.floor(eval(obj.avg))";

console.log("rounded avg: " + eval(obj.rounded));
//simulate changing properties
obj.a = Math.floor(Math.random() * 10);
obj.b = Math.floor(Math.random() * 10);
console.log("rounded avg: " + eval(obj.rounded));

The above code currently achieves what I want (using standard set values like 'a' and 'b' to calculate 'avg' then using 'avg' in a second calculation 'rounded').

Is there a better way to achieve this (ideally without the eval() calls whenever a calculated property is referenced in another property).

What I would like is for the calculated properties to act like functions (calculate their value whenever they are referenced) rather than calculating their value initially and not changing - I would like to avoid having to use () to call the functions (so that I can reference both the plain values and the calculated values the same way - just by their property name).

Upvotes: 5

Views: 8132

Answers (3)

Sebastian Simon
Sebastian Simon

Reputation: 19525

Use Getters if you don’t need to support Internet Explorer 8 or less:

var obj = {
  a:2,
  b:5,
  get avg(){
    return (this.a + this.b)/2;
  }, 
  get rounded(){
    return Math.floor(this.avg);
  }
}

Usage:

obj.a; // returns 2
obj.b; // returns 5
obj.avg; // returns 3.5
obj.rounded; // returns 3

Upvotes: 7

Robby Cornelissen
Robby Cornelissen

Reputation: 97322

Instead of using eval, use functions as follows:

var obj = {};
obj.a = 2;
obj.b = 5;
obj.avg = function() { return (this.a + this.b) / 2; };
obj.rounded = function() { return Math.floor(this.avg()); };

console.log("rounded avg: " + obj.rounded());
obj.a = Math.floor(Math.random() * 10);
obj.b = Math.floor(Math.random() * 10);
console.log("rounded avg: " + obj.rounded());

If you don't have to support old browsers, to avoid having to use parentheses when calling the functions, you could use getters as follows:

var obj = {
  a: 2,
  b: 5,
  get avg() { return (this.a + this.b) / 2; },
  get rounded() { return Math.floor(this.avg) }
}

console.log("rounded avg: " + obj.rounded);
obj.a = Math.floor(Math.random() * 10);
obj.b = Math.floor(Math.random() * 10);
console.log("rounded avg: " + obj.rounded);

Upvotes: 12

Bryce
Bryce

Reputation: 6640

It appears you are after what is called a computed property. This is a variable that is computed when it is asked for. In Javascript, you can use the Object Getter/Setter Syntax

Upvotes: 1

Related Questions