Search code examples
javascriptsettergettergetter-setter

Create multiple properties with the same getters and setters


Recently I've been writing some JavaScript program which involves the use of getters and setters. I read the MDN documentation for both methods, but I got confused trying to use them.

I want to create a series of similar properties, which will have the same getters and setters, but I don't want to rewrite every single setter and getter for every property.

Implementation

Stated the above, I tried executing the following code:

var defaultProperty = {
    set: function(val) {
        this.value = val - 1; // Just an example
    },
        
    get: function() {
        return this.value + 1; // Just an example
    }
};

var myObj = {};
Object.defineProperties(myObj, {
    foo: defaultProperty,
    bar: defaultProperty
});

Then I assigned new values to my foo and bar properties, like this:

myObj.foo = 3;
myObj.bar = 7;

And, finally, I was expecting something like this:

console.log(myObj.foo, myObj.bar);
> 3 7

But I unexpectedly got this instead:

> 7 7

It looks like the two properties are either referring to the same memory address or sharing the same setters/getters. Noticed this, I tried to solve the problem, and created each property separately, like this:

Object.defineProperties(myObj, {
    foo: {
        set: function(val) {
            this.value = val - 1;
        },
        
        get: function() {
            return this.value + 1;
        }
    },

    bar: {
        set: function(val) {
            this.value = val - 1;
        },
        
        get: function() {
            return this.value + 1;
        }
    }
});

But the result was the same:

myObj.foo = 3;
myObj.bar = 7;
console.log(myObj.foo, myObj.bar);
> 7 7

I also tried using the __defineSetter__ and __defineGetter__ functions, but the result didn't change.

My questions

Now, after several failed attempts to solve my problems, I'm wondering:

  • Is it possible to define the same setters and getters on different properties of an object?
  • If so, what am I doing wrong, and why do my properties behave like they're the same property?
  • Is there any better method to accomplish what I'm trying to do (possibly without writing each setter and getter for every property)?

Solution

  • Is it possible to define the same setters and getters on different properties of an object?

    Yes, although it's not recommended as you can see from your experience.

    what am I doing wrong, and why do my properties behave like they're the same property?

    Because they store/access the value that was set/gotten is always stored in the same .value property on your object: myObj.value == 6 so both myObj.foo and myObj.bar yield 7.

    Is there any better method to accomplish what I'm trying to do?

    Store the values in closure scope variables, and use a function to define the properties:

    function makeDefaultProperty(obj, name) {
        var value;
        return Object.defineProperty(obj, name, {
            set: function(val) {
                value = val - 1; // Just an example
            },
            get: function() {
                return value + 1; // Just an example
            }
        });
    };
    
    var myObj = {};
    makeDefaultProperty(myObj, "foo");
    makeDefaultProperty(myObj, "bar");
    

    Of course, instead of the local variable you simply might use distinct "internal" properties, and you might also use a different way of creating the common setters/getters by a function. Both applied:

    function defaultProperty(name) {
        return {
            set: function(val) {
                this[name] = val - 1; // Just an example
            },
            get: function() {
                return this[name] + 1; // Just an example
            }
        };
    }
    
    var myObj = Object.defineProperties({}, {
        foo: defaultProperty("_foo"),
        bar: defaultProperty("_bar")
    });