Search code examples
javascriptjavascript-objectssettergetter-setter

Can you add additional properties on a property with a setter?


I'm trying to create a wrapper for a type of data object. I want to be able to define a property on the wrapper which when changed has the following two effects:

  1. Changes the value of the corresponding property in the wrapped data object
  2. Adds a record of the individual change to a list of all changes so far

Having recently learned of its existence, it seemed like JavaScript's built-in getter and setter functionality (well, specifically setter) was the tool for the job. Here's the catch: I'm trying to make this roughly conform to an existing API as much as possible, and the API fields in question don't necessarily support getting the value directly, but rather querying the property to see if it matches certain conditions.

So for example, maybe I have a car object with property car.color. I want to be able to set this property by just saying car.color = "blue";, but I also want to be able to call a function car.color.isBlue(); which returns true whether the property's value is "blue" or "Blue" or "#0000FF" or any of a number of cases that I'd rather have wrapped in a function instead of directly comparing against the value every time.

I could of course easily do this by specifying an explicit property.set(value) function, but that seems to me like cruft that is best avoided if possible: it feels less natural than assignment with = and removes the (IMO) nice syntactic distinction between modifying the property and querying it.

This feels like something that JavaScript (as a general ethos thing) should be flexible enough to support, but nothing I've tried has actually worked. So, is this actually possible? And more subjectively, if the answer is yes, are there any compelling reasons why I shouldn't do it even so?


Solution

  • You can have the getter return an object that has the isBlue function.

    Something like

    function ColoredThing(color){
        var colorValue = color;
        var colorProperty = { isBlue: function(){
            return colorValue === "blue";
        }}
    
        Object.defineProperty(this, "color",{
            get: function(){
                return colorProperty;
            },
            set: function(color){
                //track history, whatever.
                colorValue = color;
            }
        });
    };
    

    Then

        var thing = new ColoredThing("blue");
        var color = thing.color
        var isBlue = color.isBlue(); //isBlue == true
        thing.color = "red";
        isBlue = color.isBlue(); //isBlue == false